当前位置: 首页 > news >正文

每日 Java 面试题分享【第 13 天】

欢迎来到每日 Java 面试题分享栏目!
订阅专栏,不错过每一天的练习

今日分享 3 道面试题目!

评论区复述一遍印象更深刻噢~

目录

  • 问题一:如何在 Java 中调用外部可执行程序或系统命令?
  • 问题二:如果一个线程在 Java 中被两次调用 start() 方法,会发生什么?
  • 问题三:栈和队列在 Java 中的区别是什么?

问题一:如何在 Java 中调用外部可执行程序或系统命令?

在 Java 中,可以通过 RuntimeProcessBuilder 调用外部可执行程序或系统命令。以下是两种方法的详细说明和使用示例。


方法 1:使用 Runtime

代码示例
public class RuntimeExample {public static void main(String[] args) {try {// 调用系统命令(如 Windows 的 dir 或 Linux 的 ls)Process process = Runtime.getRuntime().exec("ls"); // 替换为需要的命令// 获取命令执行的输出try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {String line;while ((line = reader.readLine()) != null) {System.out.println(line);}}// 等待命令执行完成int exitCode = process.waitFor();System.out.println("退出码:" + exitCode);} catch (Exception e) {e.printStackTrace();}}
}
注意
  1. 返回的 Process 对象
    • Process 表示外部进程,可以用来获取输出流、错误流,并控制进程的生命周期。
  2. 输出流的读取
    • 如果不读取或关闭进程的输出流,可能会导致进程阻塞。
优点
  • 简单直接,代码量少。
缺点
  • 不够灵活,难以传递复杂参数或处理多个 I/O。

方法 2:使用 ProcessBuilder

代码示例
import java.io.BufferedReader;
import java.io.InputStreamReader;public class ProcessBuilderExample {public static void main(String[] args) {try {// 创建 ProcessBuilderProcessBuilder processBuilder = new ProcessBuilder();// 设置要执行的命令(可带参数)processBuilder.command("ping", "www.google.com");// 合并错误流和标准输出流(可选)processBuilder.redirectErrorStream(true);// 启动进程Process process = processBuilder.start();// 读取进程输出try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {String line;while ((line = reader.readLine()) != null) {System.out.println(line);}}// 等待进程完成并获取退出码int exitCode = process.waitFor();System.out.println("退出码:" + exitCode);} catch (Exception e) {e.printStackTrace();}}
}
优点
  • 更灵活
    • 支持设置环境变量:processBuilder.environment().put("ENV_VAR", "value");
    • 支持设置工作目录:processBuilder.directory(new File("/path/to/dir"));
  • 可读性好:链式调用清晰明了。
缺点
  • Runtime 稍微复杂一点。

两种方法的对比

特性RuntimeProcessBuilder
使用简单性更简单略复杂
灵活性较低较高
支持环境变量设置不支持支持
合并输出和错误流需要手动实现直接支持(redirectErrorStream
推荐程度适合简单命令调用更推荐,适合复杂调用场景

常见使用场景

  1. 运行系统命令

    • 例如在 Linux 上执行 ls 或在 Windows 上执行 dir
    • 使用 ProcessBuildercommand 方法可以方便地传递参数。
  2. 调用外部可执行程序

    • 例如运行 .exe 文件、Python 脚本、Shell 脚本等。
    • 确保路径正确,并且有足够权限执行外部程序。
  3. 环境变量控制

    • 使用 ProcessBuilder.environment() 可以轻松传递自定义的环境变量。
  4. 读取命令输出

    • 无论是标准输出还是错误输出,Java 都可以捕获并处理。

注意事项

  1. 路径问题

    • 确保外部命令或可执行程序的路径正确,建议使用绝对路径。
    • 如果使用相对路径,请确保工作目录正确设置(ProcessBuilder.directory())。
  2. 阻塞问题

    • 如果外部进程产生大量输出,但未被读取,会导致阻塞。
    • 建议及时读取或关闭进程的输出和错误流。
  3. 跨平台性

    • 不同操作系统的命令语法可能不同,编写代码时需注意适配性。
  4. 权限问题

    • 运行外部程序可能需要特定的权限,特别是在受限的环境(如服务器)中。

扩展

如何执行带空格的命令或参数?
  • 使用 ProcessBuilder.command() 方法,将每个参数单独传递为列表元素。

    ProcessBuilder processBuilder = new ProcessBuilder();
    processBuilder.command("cmd.exe", "/c", "echo", "Hello World!");
    
如何处理输入流(标准输入)?
  • 使用 Process 对象的 getOutputStream() 方法,向外部进程写入数据。

    Process process = new ProcessBuilder("cat").start();
    try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()))) {writer.write("Hello from Java!");writer.flush();
    }
    

总结

在 Java 中调用外部程序时:

  • 简单任务使用 Runtime.getRuntime().exec()
  • 复杂任务优先使用 ProcessBuilder,以获得更好的灵活性和控制力。

问题二:如果一个线程在 Java 中被两次调用 start() 方法,会发生什么?

问题分析

在 Java 中,Thread 类的 start() 方法被用来启动一个新线程。如果尝试对同一个线程对象调用两次 start() 方法,会发生异常。


答案

如果对同一个线程对象调用两次 start() 方法,第二次调用会抛出 IllegalThreadStateException 异常。这是因为线程一旦启动后,其状态会从 NEW(新建) 转变为其他状态(如 RUNNABLETERMINATED 等)。根据 Java 线程模型,已经启动过的线程对象不能被重新启动。


代码示例

public class ThreadStartExample {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("线程正在运行…");});// 第一次启动线程thread.start();// 再次调用 start() 方法try {thread.start(); // 这里会抛出 IllegalThreadStateException} catch (IllegalThreadStateException e) {System.out.println("异常信息:线程已经启动过,不能再次调用 start()");}}
}
运行结果
线程正在运行…
异常信息:线程已经启动过,不能再次调用 start()

原因分析

1. 线程生命周期

线程的生命周期如下:

  • NEW:线程对象被创建,但未调用 start()
  • RUNNABLE:调用 start() 后,线程处于可运行状态。
  • TERMINATED:线程运行完毕,进入终止状态。

当线程离开 NEW 状态后,不能回到 NEW,因此无法再次启动。

2. start() 方法的作用

start() 方法的核心功能是:

  • 通知 JVM 创建一个新的线程(底层通过本地方法调用操作系统线程)。
  • 将线程状态从 NEW 改为 RUNNABLE,并让线程进入可调度队列。

第二次调用 start() 时,由于线程不再是 NEW 状态,JVM 会拒绝这个操作,抛出异常。

3. 设计初衷

Java 线程模型的设计目的是让每个 Thread 对象只启动一次,避免复杂的状态管理(如重新初始化线程)。如果需要再次启动线程,应该创建一个新的 Thread 实例。


扩展讲解

如何避免这种问题?
  • 检查线程状态:如果需要对线程进行管理,可以通过 Thread.getState() 方法检查其状态。

    示例代码:

    public class ThreadStateCheck {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("线程运行中…");});System.out.println("线程状态:" + thread.getState()); // NEWthread.start();System.out.println("线程状态:" + thread.getState()); // RUNNABLE 或 TERMINATEDtry {thread.start(); // 再次调用会抛异常} catch (IllegalThreadStateException e) {System.out.println("异常:线程已经启动过");}}
    }
    
  • 重新创建线程对象:如果需要重复执行任务,可以通过新建线程实现:

    Thread thread1 = new Thread(() -> System.out.println("任务 1"));
    thread1.start();Thread thread2 = new Thread(() -> System.out.println("任务 2"));
    thread2.start();
    
线程池的使用

如果需要多次执行相同任务,推荐使用线程池(ExecutorService),而非手动管理 Thread 对象。例如:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);Runnable task = () -> System.out.println("任务正在运行…");executor.execute(task); // 启动任务executor.execute(task); // 再次启动任务executor.shutdown();}
}

线程池可以高效管理线程复用,避免直接操作线程带来的复杂性。


总结

  1. 对一个线程对象调用两次 start() 方法会抛出 IllegalThreadStateException
  2. 每个线程对象只能启动一次。如果需要重新运行任务,需要新建线程实例或使用线程池。
  3. 推荐使用线程池(如 ExecutorService)来管理多次任务执行,避免手动控制线程的复杂性。

问题三:栈和队列在 Java 中的区别是什么?

栈和队列的区别

栈(Stack)和队列(Queue)是两种常用的线性数据结构,它们在数据存取方式和应用场景上有显著的区别。以下从定义、操作规则、实现和应用等方面进行分析:


1. 栈 (Stack)

定义

栈是一种**后进先出(LIFO, Last In First Out)**的数据结构,即最后插入的数据最先被取出。

核心操作
  • push(E item):将元素压入栈顶。
  • pop():移除并返回栈顶元素。
  • peek():仅返回栈顶元素,但不移除。
Java 实现
  • 使用 java.util.Stack 类。

  • 示例代码:

    import java.util.Stack;public class StackExample {public static void main(String[] args) {Stack<Integer> stack = new Stack<>();stack.push(10);stack.push(20);stack.push(30);System.out.println("栈顶元素:" + stack.peek()); // 输出 30System.out.println("弹出元素:" + stack.pop()); // 输出 30System.out.println("弹出后栈顶:" + stack.peek()); // 输出 20}
    }
    

2. 队列 (Queue)

定义

队列是一种**先进先出(FIFO, First In First Out)**的数据结构,即最先插入的数据最先被取出。

核心操作
  • add(E item)offer(E item):将元素添加到队列尾部。
  • remove()poll():移除并返回队列头部元素。
  • element()peek():仅返回队列头部元素,但不移除。
Java 实现
  • 使用 java.util.Queue 接口的实现类,例如 LinkedListArrayDeque

  • 示例代码:

    import java.util.LinkedList;
    import java.util.Queue;public class QueueExample {public static void main(String[] args) {Queue<Integer> queue = new LinkedList<>();queue.offer(10);queue.offer(20);queue.offer(30);System.out.println("队列头元素:" + queue.peek()); // 输出 10System.out.println("移除元素:" + queue.poll()); // 输出 10System.out.println("移除后队列头:" + queue.peek()); // 输出 20}
    }
    

3. 栈与队列的主要区别

特性栈 (Stack)队列 (Queue)
访问规则后进先出(LIFO)先进先出(FIFO)
常用方法push()pop()peek()offer()poll()peek()
插入位置栈顶队尾
移除位置栈顶队头
实现方式使用 java.util.Stack使用 java.util.Queue 接口及实现类
常见应用场景递归、括号匹配、函数调用栈、回溯算法消息队列、任务调度、广度优先搜索

4. 特殊队列:双端队列 (Deque)

定义

双端队列(Deque, Double-Ended Queue)允许在队首和队尾同时插入和移除元素。

实现
  • 使用 java.util.ArrayDequejava.util.LinkedList

  • 示例代码:

    import java.util.Deque;
    import java.util.ArrayDeque;public class DequeExample {public static void main(String[] args) {Deque<Integer> deque = new ArrayDeque<>();deque.addFirst(10); // 插入到队首deque.addLast(20);  // 插入到队尾System.out.println("队首元素:" + deque.peekFirst()); // 输出 10System.out.println("队尾元素:" + deque.peekLast());  // 输出 20deque.removeFirst(); // 移除队首deque.removeLast();  // 移除队尾}
    }
    
应用
  • 双端队列可用于实现栈或队列的功能,也可以用作滑动窗口算法等高级场景。

5. 实际应用场景

  • 栈:
    • 函数调用栈
    • 括号匹配
    • 表达式求值
    • 深度优先搜索(DFS)
  • 队列:
    • 任务调度
    • 广度优先搜索(BFS)
    • 消息队列
    • 缓冲区管理

总结

  • 栈是后进先出的数据结构,常用于递归、回溯等场景。
  • 队列是先进先出的数据结构,适合任务调度和广度优先搜索等场景。
  • 双端队列是栈和队列的通用化版本,既可以实现栈的功能,也可以实现队列的功能。

总结

今天的 3 道 Java 面试题,您是否掌握了呢?持续关注我们的每日分享,深入学习 Java 面试的各个细节,快速提升技术能力!如果有任何疑问,欢迎在评论区留言,我们会第一时间解答!

明天见!🎉

相关文章:

每日 Java 面试题分享【第 13 天】

欢迎来到每日 Java 面试题分享栏目&#xff01; 订阅专栏&#xff0c;不错过每一天的练习 今日分享 3 道面试题目&#xff01; 评论区复述一遍印象更深刻噢~ 目录 问题一&#xff1a;如何在 Java 中调用外部可执行程序或系统命令&#xff1f;问题二&#xff1a;如果一个线程…...

探究 Facebook 隐私安全发展方向,未来走向何方?

随着社交媒体的普及&#xff0c;隐私和数据安全问题成为了全球关注的焦点。Facebook&#xff0c;作为全球最大的社交平台之一&#xff0c;其隐私安全问题尤其引人注目。近年来&#xff0c;随着用户数据泄露事件的不断发生&#xff0c;Facebook 不断调整其隐私政策&#xff0c;探…...

第三十一周学习周报

目录 摘要Abstract文献阅读总体架构实验分析 知识复习总结 摘要 在本周阅读的文献中&#xff0c;作者提出了一种基于生成对抗网络&#xff08;GAN&#xff09;和长短期记忆网络&#xff08;LSTM&#xff09;融合模型的连续管钻井参数预测方法&#xff0c;旨在提高连续管钻井的…...

白嫖一个可以公网访问、带评论和图床的博客系统

这里我来把搭建这个网站的过程记录下&#xff0c;可供新手朋友搭建 完成github page的创建 首先先打开github官网&#xff0c;然后打开your repositories这个标签 然后新建一个repositories&#xff0c;名字是比较特殊的&#xff0c;为<username>.github.io这个格式&am…...

定时器、计数器

定时器&#xff1a;TON TOF TONR&#xff1a;保持型接通定时器 TP:脉冲定时器&#xff1a;触发一次&#xff0c;就开始计时 TP&#xff1a;按下I0.1 TP开始计时&#xff0c;Q电开始有电&#xff0c;时间到Q点失电 计数器&#xff1a;CTU加 CTD减 CTUD加减 两个方法&#xf…...

Ubuntu Server连接wifi

背景 家里服务器放在客厅太吵了, 准备挪到阳台, 所以买了TP wifi接收器, 因此需要配置wifi连接. 刚开始买了Tenda Ax300, 结果不支持服务器系统, 买前还是得和客服交流交流. 准备 驱动安装 对于windows系统来说, 这款接收器是免驱的, 但在linux上需要安装相应型号驱动 安装…...

关于MySQL InnoDB存储引擎的一些认识

文章目录 一、存储引擎1.MySQL中执行一条SQL语句的过程是怎样的&#xff1f;1.1 MySQL的存储引擎有哪些&#xff1f;1.2 MyIsam和InnoDB有什么区别&#xff1f; 2.MySQL表的结构是什么&#xff1f;2.1 行结构是什么样呢&#xff1f;2.1.1 NULL列表&#xff1f;2.1.2 char和varc…...

深入剖析SpringBoot启动机制:run()方法详尽解读

摘要 本文深入解析SpringBoot的启动机制&#xff0c;以run()方法为核心&#xff0c;逐步追踪并详细解释其关键步骤。首先探讨run()方法的工作原理&#xff0c;然后深入代码层面分析各个关键环节。文章提供刷新后钩子和启动后任务的代码示例&#xff0c;帮助读者理解SpringBoot源…...

Nginx中部署多个前端项目

1&#xff0c;准备前端项目 tlias系统的前端资源 外卖项目的前端资源 2&#xff0c;nginx里面的html文件夹中新建&#xff0c;tlias和sky两个文件夹。 切记这是在nginx/html下创建的 mkdir sky mkdir tlias 把tlias和sky的资源都放到对应的文件夹中 3&#xff0c;编辑配置ngi…...

1688寻源通:赋能跨境贸易的高效业务平台

前言 在全球化的浪潮下&#xff0c;跨境电商已成为推动经济发展的重要力量。作为国内领先的B2B电商平台&#xff0c;1688凭借其强大的供应链资源和创新技术&#xff0c;推出了“寻源通”业务&#xff0c;旨在帮助国内供应商和跨境采购商实现更高效、更精准的供需匹配&#xff…...

JVM深入学习(一)

目录 一.JVM概述 1.1 为什么要学jvm&#xff1f; 1.2 jvm的作用 1.3 jvm内部构造 二.JVM类加载 2.1类加载过程 2.2类加载器 2.3类加载器的分类 2.4双亲委派机制 三.运行时数据区 堆空间区域划分&#xff08;堆&#xff09; 为什么分区(代)&#xff1f;&#xff08…...

Qt Creator 15.0.0如何更换主题和字体

1.打开Qt Creator 15.0.0 (Community)&#xff0c; 2.点击编辑栏3.点击Preferences... 4.修改主题&#xff0c;点击环境&#xff0c;修改Theme:栏 5.修改字体大小&#xff0c;点击文本编辑器&#xff0c;修改字号栏。&#xff0c;修改Theme:栏...

“大模型横扫千军”背后的大数据挖掘--浅谈MapReduce

文章目录 O 背景知识1 数据挖掘2 邦费罗尼原则3 TF.IDF4 哈希函数5 分布式文件系统 一、MapReduce基本介绍1. Map 任务2. 按键分组3. Reduce 任务4. 节点失效处理5.小测验&#xff1a;在一个大型语料库上有100个map任务和若干reduce任务&#xff1a; 二、基于MapReduce的基本运…...

shallowRef和shallowReactive的用法以及使用场景和ref和reactive的区别

Vue3 浅层响应式 API 1. ref vs shallowRef 1.1 基本概念 ref: 深层响应式&#xff0c;会递归地将对象的所有属性转换为响应式shallowRef: 浅层响应式&#xff0c;只有 .value 的改变会触发更新&#xff0c;不会递归转换对象的属性 1.2 使用对比 // ref 示例 const deepRe…...

maven、npm、pip、yum官方镜像修改文档

文章目录 Maven阿里云网易华为腾讯云 Npm淘宝腾讯云 pip清华源阿里中科大华科 Yum 由于各博客繁杂&#xff0c;本文旨在记录各常见镜像官网&#xff0c;及其配置文档。常用镜像及配置可评论后加入 Maven 阿里云 官方文档 setting.xml <mirror><id>aliyunmaven&l…...

HTML5+SVG+CSS3实现雪中点亮的圣诞树动画效果源码

源码介绍 这是一款基于HTML5SVGCSS3实现雪中点亮的圣诞树动画效果源码。画面中的圣诞树矗立在雪地中&#xff0c;天上飘落着雪花。当鼠标滑过圣诞树时&#xff0c;可见到圣诞树上的灯光闪烁&#xff0c;同时左下角探出雪怪模样的半个脑袋&#xff0c;四处张望着。整体画面栩栩…...

HTML-新浪新闻-实现标题-样式1

用css进行样式控制 css引入方式&#xff1a; --行内样式&#xff1a;写在标签的style属性中&#xff08;不推荐&#xff09; --内嵌样式&#xff1a;写在style标签中&#xff08;可以写在页面任何位置&#xff0c;但通常约定写在head标签中&#xff09; --外联样式&#xf…...

Linux-day10

第21章 Linux高级篇-日志管理 日志介绍和实例 基本介绍 系统常用的日志 日志服务 日志服务原理图 在这个配置文件里面记录了日志服务程序 日志管理服务rsyslogd -v是反向匹配 invert 日志服务配置文件 时间、主机、是由哪个程序或者服务发生的、事件信息 自定义日志服务 日…...

【Unity3D】《跳舞的线》游戏的方块单方向拉伸实现案例

通过网盘分享的文件&#xff1a;CubeMoveMusic.unitypackage 链接: https://pan.baidu.com/s/1Rq-HH4H9qzVNtpQ84WXyUA?pwda7xn 提取码: a7xn 运行游戏点击空格动态创建拉伸的方块&#xff0c;由Speed控制速度&#xff0c;新方向是随机上下左右生成。 using System.Collect…...

AI智能日志分析系统

文章目录 1.combinations-intelligent-analysis-starter1.目录结构2.pom.xml3.自动配置1.IntelligentAnalysisAutoConfiguration.java2.spring.factories 2.combinations-intelligent-analysis-starter-demo1.目录结构2.pom.xml3.application.yml4.IntelligentAnalysisApplicat…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)

在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...

32单片机——基本定时器

STM32F103有众多的定时器&#xff0c;其中包括2个基本定时器&#xff08;TIM6和TIM7&#xff09;、4个通用定时器&#xff08;TIM2~TIM5&#xff09;、2个高级控制定时器&#xff08;TIM1和TIM8&#xff09;&#xff0c;这些定时器彼此完全独立&#xff0c;不共享任何资源 1、定…...