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

定时/延时任务-ScheduledThreadPoolExecutor的使用

文章目录

  • 1. 概要
  • 2. 固定速率和固定延时
    • 2.1 固定速率
    • 2.2 固定延时
  • 3. API 解释
    • 3.1 schedule
    • 3.2 固定延时 - scheduleWithFixedDelay
    • 3.2 固定速率 - scheduleWithFixedDelay
  • 4. 小结

1. 概要

前三篇文章的地址:

  1. 定时/延时任务-自己实现一个简单的定时器
  2. 定时/延时任务-Timer用法
  3. 定时/延时任务-细说Timer源码

ScheduledThreadPoolExecutor Java 并发包 (java.util.concurrent) 中的一个类,同时也是 ThreadPoolExecutor 的一个子类,这就意味者 ScheduledThreadPoolExecutor 不像 Timer 中使用单个线程去执行任务,ScheduledThreadPoolExecutor 使用了线程池去执行,同时 ScheduledThreadPoolExecutor 也具备了 Timer 中的各种功能。

2. 固定速率和固定延时

2.1 固定速率

固定速率 策略表示任务在固定的时间间隔内重复执行,不管任务的执行时间有多长,如果任务的执行时间超过了时间间隔,那么下一个任务会在当前任务执行完毕之后就会马上开始执行,下面是一个例子:假设我们设置了一个固定速率为 5 的任务,从 0s 开始执行,也就是说这个任务 5s 执行一次:

  • 第一次执行:0s 开始执行一次,假设执行时间是 3s
  • 第二次执行:5s 开始执行第二次,假设执行的时候被阻塞了,执行了 8s
  • 第三次执行:13s 开始执行第三次,假设执行的时候被阻塞了,执行了 3s
  • 第四次执行:16s 开始执行第四次,假设执行的时候没有被阻塞
  • 第四次执行:20s 开始执行第五次,假设执行的时候没有被阻塞


2.2 固定延时

固定延时 策略表示任务在当前任务执行完成之后,固定延时一段时间再执行下一个任务,下面是一个例子:假设我们设置了一个固定速率为 5 的任务,从 0s 开始执行,也就是说这个任务 5s 执行一次:

  • 第一次执行:0s 开始执行一次,假设执行时间是 3s
  • 第二次执行:8s 开始执行第二次,假设执行的时候被阻塞了,执行了 8s
  • 第三次执行:21s 开始执行第三次,假设执行的时候被阻塞了,执行了 3s
  • 第四次执行:29 开始执行第四次,假设执行的时候没有被阻塞
  • 第四次执行:34s 开始执行第五次,假设执行的时候没有被阻塞

上面的例子中其实固定速率的执行和 Timer 是一样的,但是固定延时有点不一样,不知道你有没有发现,固定延时下执行的时候每一个任务和前一个任务的时间间隔一定是 任务执行时间 + 延时时间,其实相比于 TimerScheduledThreadPoolExecutor 的固定延时看起来更像是 “正宗” 一点的固定延时


3. API 解释

3.1 schedule

还是老规矩,先看下 ScheduledThreadPoolExecutor 的几个 API,看看用法是什么样的,首先就是 schedule 方法,这个方法就是普通的延时方法,只执行一次,非周期调度

public class Pra {public static void main(String[] args) {ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(16);Thread thread = new Thread(() -> {try {System.out.println("Thread-Current: " + Thread.currentThread().getName() + ", time = " + getTime());if (Math.random() < 0.5) {System.out.println("sleep: 3s");Thread.sleep(3000);} else {System.out.println("sleep: 8s");Thread.sleep(8000);}} catch (InterruptedException e) {e.printStackTrace();}}, "thread-executor-run");executor.schedule(thread, 0, TimeUnit.SECONDS);}private static String getTime() {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");return sdf.format(new Date());}}

执行结果如下所示,延迟 0s 就开始执行任务
在这里插入图片描述
ScheduledThreadPoolExecutor 也提供了一个 callable 类型的任务的实现,使用 Callable 的好处就是可以获取任务的实现返回值,如下例子所示:

public class Pra {public static void main(String[] args) {ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(16);// 创建一个 Callable 任务Callable<Integer> task = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {System.out.println("Task is running on thread: " + Thread.currentThread().getName());return 1; // 返回结果}};// 调度 Callable 任务,在 0 秒后执行ScheduledFuture<Integer> future = executor.schedule(task, 0, TimeUnit.SECONDS);try {// 获取任务的结果Integer result = future.get();System.out.println("Task result: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}private static String getTime() {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");return sdf.format(new Date());}}

输出结果如下所示:
在这里插入图片描述

3.2 固定延时 - scheduleWithFixedDelay

public class Pra {public static void main(String[] args) {ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(16);Thread thread = new Thread(() -> {try {System.out.println("Thread-Current: " + Thread.currentThread().getName() + ", time = " + getTime());if (Math.random() < 0.5) {System.out.println("sleep: 3s");Thread.sleep(3000);} else {System.out.println("sleep: 8s");Thread.sleep(8000);}} catch (InterruptedException e) {e.printStackTrace();}}, "thread-executor-run");executor.scheduleWithFixedDelay(thread, 0, 5, TimeUnit.SECONDS);}private static String getTime() {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");return sdf.format(new Date());}}

输入如下所示:
在这里插入图片描述
来分析一下:

  • 首先第一次任务 2024-11-24 19:19:36:698 启动,然后执行时间 3s
  • 第二次任务在 2024-11-24 19:19:44:718 启动,跟第一次任务相差 8s,延时 = 5s + 3s = 8s
  • 第三次任务在 2024-11-24 19:19:52:741 启动,跟第二次任务相差 8s,延时 = 5s + 3s = 8s
  • 第四次任务在 2024-11-24 19:20:05:760 启动,跟第三次任务相差 13s,延时 = 5s + 8s = 13s
  • 第五次任务在 2024-11-24 19:20:13:773 启动,跟第四次任务相差 8s,延时 = 5s + 3s = 8s
  • 第六次任务在 2024-11-24 19:20:26:787 启动,跟第五次任务相差 13s,延时 = 5s + 8s = 13s

可以看到 scheduleWithFixedDelay 的延时是相对于当前时间 + 延时时间的,跟 Timer 的固定延时任务有点不同

3.2 固定速率 - scheduleWithFixedDelay

public class Pra {public static void main(String[] args) {ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(16);Thread thread = new Thread(() -> {try {System.out.println("Thread-Current: " + Thread.currentThread().getName() + ", time = " + getTime());if (Math.random() < 0.5) {System.out.println("sleep: 3s");Thread.sleep(3000);} else {System.out.println("sleep: 8s");Thread.sleep(8000);}} catch (InterruptedException e) {e.printStackTrace();}}, "thread-executor-run");executor.scheduleAtFixedRate(thread, 0, 5, TimeUnit.SECONDS);}private static String getTime() {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");return sdf.format(new Date());}}

输出结果如下:
在这里插入图片描述
来分析下上面的执行流程,需要注意的是,ScheduledThreadPoolExecutor 的固定速率任务会在当前任务执行完之后再添加下一次要执行的任务

  • 首先第一次任务 2024-11-24 16:23:25:762 启动,然后执行时间 8s,执行完之后会添加一个 2024-11-24 16:23:30 s 执行的任务,当前时间 2024-11-24 16:23:33 s
  • 第二次任务在 2024-11-24 16:23:33:770 启动,因为 2024-11-24 16:23:33:770 超过了 2024-11-24 16:23:30 s 这个时间点, 所以立刻执行,执行时间 3s,执行完之后往队列里面添加一个 2024-11-24 16:23:35 s 执行的任务,当前时间 2024-11-24 16:23:36 s
  • 第二次任务在 2024-11-24 16:23:36:784 启动,因为 2024-11-24 16:23:36:784 超过了 2024-11-24 16:23:35 s 这个时间点, 所以立刻执行,执行时间 3s,执行完之后往队列里面添加一个 2024-11-24 16:23:40 s 执行的任务,当前时间 2024-11-24 16:23:39 s
  • 第四次任务在 2024-11-24 16:23:40:739 启动,因为第三个任务执行完之后时间是 2024-11-24 16:23:39 s,还没有到第四个任务执行的时间点,这时候就等待,等到 2024-11-24 16:23:40:739,执行时间 3s,执行完之后往队列里面添加一个 2024-11-24 16:23:45 s 执行的任务,执行完的时间当前是 2024-11-24 16:23:42 s
  • 第五次任务在 2024-11-24 16:23:45:751 启动,因为第四个任务执行完之后时间是 2024-11-24 16:23:42 s,还没有到第五个任务执行的时间点,这时候就等待,等到 2024-11-24 16:23:45:751,执行时间 8s,执行完之后往队列里面添加一个 2024-11-24 16:23:50 s 执行的任务,执行完的时间当前是 2024-11-24 16:23:53 s
  • 第六次任务在 2024-11-24 16:23:53:763 启动,因为第六个任务执行时间是 2024-11-24 16:23:50 s,而执行完第五个任务已经是 2024-11-24 16:23:53 s了,超过任务的执行时间,所以会立马执行,执行时间 3s,执行完后往队列里面添加一个 2024-11-24 16:23:55 s 的任务,当前时间是 2024-11-24 16:23:56 s

其实上面的解释中可以把后面的毫秒去掉,这样比较方便理解

4. 小结

上面就是几个 API 了,其中固定速率的和 Timer 的实现方式有点不同,后续文章中,我会对 ScheduledThreadPoolExecutor 的源码进行详细的解析,当然在解析 ScheduledThreadPoolExecutor 之前首先需要知道下线程池的工作原理和工作流程,所以下一篇文章,我会说下线程池的工作原理

相关文章:

定时/延时任务-ScheduledThreadPoolExecutor的使用

文章目录 1. 概要2. 固定速率和固定延时2.1 固定速率2.2 固定延时 3. API 解释3.1 schedule3.2 固定延时 - scheduleWithFixedDelay3.2 固定速率 - scheduleWithFixedDelay 4. 小结 1. 概要 前三篇文章的地址&#xff1a; 定时/延时任务-自己实现一个简单的定时器定时/延时任…...

自编码器(一)

其实自编码器也可以算是自监督学习的一环&#xff0c;因 此我们可以再简单回顾一下自监督学习的框架。如图1.1所示&#xff0c;首先你有大量的没有标注的 数据&#xff0c;用这些没有标注的数据&#xff0c;你可以去训练一个模型&#xff0c;你必须设计一些不需要标注数据的 任…...

Spring Cloud(Kilburn 2022.0.2版本)系列教程(五) 服务网关(SpringCloud Gateway)

Spring Cloud(Kilburn 2022.0.2版本)系列教程(五) 服务网关(SpringCloud Gateway) 一、服务网关 1.1 什么是网关 在微服务架构中&#xff0c;服务网关是一个至关重要的组件。它作为系统的入口&#xff0c;负责接收客户端的请求&#xff0c;并将这些请求路由到相应的后端服务…...

40分钟学 Go 语言高并发:Go程序性能优化方法论

Go程序性能优化方法论 一、性能指标概述 指标类型关键指标重要程度优化目标CPU相关CPU使用率、线程数、上下文切换⭐⭐⭐⭐⭐降低CPU使用率&#xff0c;减少上下文切换内存相关内存使用量、GC频率、对象分配⭐⭐⭐⭐⭐减少内存分配&#xff0c;优化GC延迟指标响应时间、处理延…...

一文解析Kettle开源ETL工具!

ETL&#xff08;Extract, Transform, Load&#xff09;工具是用于数据抽取、转换和加载的软件工具&#xff0c;用于支持数据仓库和数据集成过程。Kettle作为传统的ETL工具备受用户推崇。本文就来详细说下Kettle。 一、Kettle是什么&#xff1f; Kettle 是一款开源的 ETL&#x…...

Tomcat新手成长之路:安装部署优化全解析(上)

文章目录 1.Tomcat简介2.Tomcat原理架构2.1.总体架构2.2.连接器2.2.1.具体功能2.2.2.IO模型2.2.3.逻辑处理流程2.2.4.内部处理流程 2.3.容器2.4.启动过程2.5.请求过程 3.Tomcat适用场景4.Tomcat与其他Web容器对比5.Tomcat安装和启动5.1.Java环境变量5.2.系统服务5.3.启动关闭 6…...

跟我学C++中级篇——通信的数据的传递形式

一、通信的数据传递 在开发程序中&#xff0c;无可避免的会进行数据的传递。这种传递方式有很多种&#xff0c;字节流、消息、Json、参数以及对象甚至可能的方法。那么在传递这些数据时&#xff0c;如何正确的采用更合适的方法&#xff0c;就成为了一个设计的首选的问题。 二…...

C语言 qsort及应用

qsort及应用 qsort:快速排序函数,需要引用stdlib.h文件. void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *, const void *) ); 参数: base:需要排序的数组 num:数据个数(数组长度) width:每个数据的字节数(sizeof(数据类型)) compa…...

【C语言】连接陷阱探秘(4):检查外部类型

目录 一、外部类型概述 1.1. 外部类型的重要性 1.2. 外部类型在C语言中的使用 1.3. 注意事项 二、常见的外部类型陷阱 2.1. 结构体和联合体的大小不匹配 2.1.1. 示例代码 2.1.2. 正确的做法 2.2. 枚举类型的值不匹配 2.3. 函数签名不一致 2.3.1. 函数签名不一致的问…...

打造双层环形图:基础与高级渐变效果的应用

在数据可视化领域&#xff0c;环形图因其独特的展示方式而广受欢迎。今天&#xff0c;我们将通过ECharts库来创建一个具有双层渐变效果的高级环形图。本文将详细介绍如何实现这种视觉效果。 1. 环形图基础 首先&#xff0c;我们需要了解环形图的基本构成。环形图由内外两个圆…...

【Git】Git 完全指南:从入门到精通

Git 完全指南&#xff1a;从入门到精通 Git 是现代软件开发中最重要的版本控制工具之一&#xff0c;它帮助开发者高效地管理项目&#xff0c;支持分布式协作和版本控制。无论是个人项目还是团队开发&#xff0c;Git 都能提供强大的功能来跟踪、管理代码变更&#xff0c;并保障…...

【mac】mac自动定时开关机和其他常用命令,管理电源设置的工具pmset

一、操作步骤 1、打开终端 2、pmset 是用于管理电源设置的强大工具&#xff0c;我们将使用这个命令 &#xff08;1&#xff09;查询当前任务 pmset -g sched查看到我当前的设置是 唤醒电源开启在 工作日的每天早上8点半 上班时不用手动开机了 &#xff08;2&#xff09;删…...

【Leecode】Leecode刷题之路第62天之不同路径

题目出处 62-不同路径-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 62-不同路径-官方解法 方法1&#xff1a;动态规划 思路&#xff1a; 代码示例&#xff1a;&#xff08;Java&…...

基于深度学习的手势识别算法

基于深度学习的手势识别算法 概述算法原理核心逻辑效果演示使用方式参考文献 概述 本文基于论文 [Simple Baselines for Human Pose Estimation and Tracking[1]](ECCV 2018 Open Access Repository (thecvf.com)) 实现手部姿态估计。 手部姿态估计是从图像或视频帧集中找到手…...

helm部署golang服务

Helm 是 Kubernetes 的一个包管理工具,类似于 Linux 中的 apt 或 yum。它使得在 Kubernetes 上部署和管理应用程序变得更加简单和高效。 安装 https://get.helm.sh/helm-v3.16.3-linux-amd64.tar.gz具体版本号可以在github上看到最新的版本号,然后替换上面链接来获取。gith…...

DreamCamera2相机预览变形的处理

最近遇到一个问题&#xff0c;相机更换了摄像头后&#xff0c;发现人像角度顺时针旋转了90度&#xff0c;待人像角度正常后&#xff0c;发现 预览时图像有挤压变形&#xff0c;最终解决。在此记录 一人像角度的修改 先放示意图 设备预览人像角度如图1所示&#xff0c;顺时针旋…...

Mysql误删表中数据与误删表的恢复方法

查看数据库是否开启binlog日志 mysql> show variables like %log_bin%; ------------------------------------------------------------------------ | Variable_name | Value | ------------------------------------…...

lapack、blas、solver库的区别和联系

LAPACK、BLAS、Solver 库 是数值计算领域的重要组成部分,它们各自的功能和设计目标有所不同,但也存在密切的联系。 1. 概述 库主要功能设计目标BLAS提供基础的线性代数操作,如向量运算、矩阵-向量乘法、矩阵-矩阵乘法等。提供高度优化的基础线性代数操作,作为更高级库的底层…...

deepin 安装 chrome 浏览器

deepin 安装 chrome 浏览器 最近好多小伙伴儿和我说 deepin 无法安装最新的谷歌浏览器 其实是因为最新的 谷歌浏览器 其中的一个依赖需要提前安装 提前安装依赖然后再安装谷歌浏览器就可以了 安装 fonts-liberationsudo apt -y install fonts-liberation安装 chrome 浏览器sudo…...

永久免费的PDF万能水印删除工具

永久免费的PDF万能水印删除工具 1.简介 PDF万能水印删除工具&#xff0c;可以去除99.9%的PDF水印。例如&#xff1a;XObject水印&#xff08;含图片水印&#xff09;、文本水印、绘图水印/曲线水印、注释水印、工件水印、剪切路径水印等等。本软件是永久免费&#xff0c;无有…...

Linux网络——NAT/代理服务器

一.NAT技术 1.NAT IP转换 之前我们讨论了, IPv4 协议中, IP 地址数量不充足的问题&#xff0c;NAT 技术就是当前解决 IP 地址不够用的主要手段, 是路由器的一个重要功能。 NAT 能够将私有 IP 对外通信时转为全局 IP. 也就是一种将私有 IP 和全局IP 相互转化的技术方法: 很…...

大米中的虫子检测-检测储藏的大米中是否有虫子 支持YOLO,VOC,COCO格式标注,4070张图片的数据集

大米中的虫子检测-检测储藏的大米中是否有虫子 支持YOLO&#xff0c;VOC&#xff0c;COCO格式标注&#xff0c;4070张图片的数据集 数据集分割 4070总图像数 训练组 87&#xff05; 3551图片 有效集 9&#xff05; 362图片 测试集 4% 157图片 预处理 自动定向…...

基于Java的小程序电商商城开源设计源码

近年来电商模式的发展越来越成熟&#xff0c;基于 Java 开发的小程序电商商城开源源码&#xff0c;为众多开发者和企业提供了构建个性化电商平台的有力工具。 基于Java的电子商城购物平台小程序的设计在手机上运行&#xff0c;可以实现管理员&#xff1b;首页、个人中心、用户…...

node.js基础学习-fs模块-文件操作(六)

一、前言 fs模块是 Node.js 内置的文件系统&#xff08;File System&#xff09;模块&#xff0c;它提供了一系列用于与文件系统进行交互的方法。通过fs模块&#xff0c;可以对文件或目录进行读取、写入、删除、重命名、查询状态等操作&#xff0c;这使得 Node.js 能够很好地处…...

设计模式:11、迭代器模式(游标)

目录 0、定义 1、迭代器模式的四种角色 2、迭代器模式的UML类图 3、示例代码 4、迭代器的next()方法与集合的get(int index)方法的效率对比&#xff08;LinkedList为例&#xff09; 0、定义 提供一种方法顺序访问一个聚合对象中的各个元素&#xff0c;而又不需要暴露该对象…...

Oracle SCN与时间戳的映射关系

目录 一、基本概述 二、相关操作 三、参考文档 一、基本概述 Oracle 数据库中的 SYS.SMON_SCN_TIME 表是一个关键的内部表&#xff0c;主要用于记录过去时间段中SCN与具体的时间戳之间的映射关系。这种映射关系可以帮助用户将 SCN 值转换为可读性更强的时间戳&#xff0c;从而…...

【广告投放系统】头条可视化投放平台vue3+element-plus+vite落地历程和心得体会

前言 hallo&#xff0c;又是许久未见&#xff0c;昨天也是正式把公司内部的广告投放平台暂时落地&#xff0c;我也即将离开待了两年多的地方。言归正传&#xff0c;由于头条广告后台的升级改版&#xff0c;因此为了满足内部投放需求&#xff0c;做了一个可视化的投放平台&…...

Gazebo插件相机传感器(可订阅/camera/image_raw话题)

在仿真环境中使用相机传感器&#xff0c;通常需要结合Gazebo插件来实现。Gazebo是一个功能强大的机器人仿真工具&#xff0c;支持多种传感器模型&#xff0c;包括相机。下面是如何在Gazebo中使用相机传感器的详细步骤。 1. 修改Xacro文件以包含Gazebo插件 首先&#xff0c;修…...

华三(HCL)和华为(eNSP)模拟器共存安装手册

接上章叙述&#xff0c;解决同一台PC上同时部署华三(HCL)和华为(eNSP&#xff09;模拟器。原因就是华三HCL 的老版本如v2及以下使用VirtualBox v5版本&#xff0c;可以直接和eNSP兼容Oracle VirtualBox&#xff0c;而其他版本均使用Oracle VirtualBox v6以上的版本&#xff0c;…...

信息学奥赛一本通 1448:【例题1】电路维修 | 洛谷 P4667 [BalticOI 2011 Day1] Switch the Lamp On 电路维修

【题目链接】 ybt 1448&#xff1a;【例题1】电路维修 洛谷 P4667 [BalticOI 2011 Day1] Switch the Lamp On 电路维修 【题目考点】 1. 双端队列广搜&#xff08;0-1BFS&#xff09; 【解题思路】 整个电路是由一个个的正方形的电路元件组成&#xff0c;每个正方形有四个…...

做医院的系统网站怎么做/app开发需要多少钱

基于乐鑫ESP8266的SOC解决方案参考文章&#xff1a; &#xff08;1&#xff09;基于乐鑫ESP8266的SOC解决方案 &#xff08;2&#xff09;https://www.cnblogs.com/dapangsen/p/6392621.html &#xff08;3&#xff09;https://www.codeprj.com/blog/618b2d1.html 备忘一下…...

wordpress seo 主题/企业营销策划是做什么的

前面给大家分享了pandas.merge用法详解&#xff0c;这节分享pandas数据合并处理的姊妹篇&#xff0c;pandas.concat用法详解&#xff0c;参考利用Python进行数据分析与pandas官网进行整理。 pandas.merge参数列表如下图&#xff0c;其中只有objs是必须得参数&#xff0c;另外常…...

网站维护 代码/今日国际新闻最新消息大事

springboot使用lombok省略set和get方法使用lombok省略setget方法更多文章欢迎访问个人博客 www.herobin.top 使用lombok省略setget方法 首先在pom中加入lombok依赖包 pom.xml <dependency><groupId>org.projectlombok</groupId><artifactId>lombok…...

嘉兴优化网站哪家好/如何提高网站搜索排名

复习Python的第三十九天 习题 44 : 给你的游戏打分 从现在开始你要学会“自给自足”&#xff0c;以前是我牵着你前行&#xff0c;以后就得靠你自己了。 一开始你会觉得很困难并且很不习惯&#xff0c;但只要坚持下去&#xff0c;你就会培养出自己解决问题的能力。 你还会找出…...

港口建设申报网站/网络营销seo优化

做好笔记&#xff0c;打好基础&#xff0c;往高处走。供自己参考&#xff0c;同时欢迎大家指正。1、在官网下载好新版的免安装文件&#xff0c;我的是5.7.20。解压到自定义目录。2、配置环境变量&#xff1a;右键计算机-->属性-->高级系统设置-->环境变量 在path里最…...

wordpress上传的图片不显示/搜索引擎有哪些网站

进程控制本文介绍进程创建fork函数fork函数的返回值fork函数的使用写时拷贝fork用法fork调用失败的原因进程终止进程退出的场景进程退出码进程正常退出return exit _exit之间的区别和联系进程异常退出进程等待进程等待的必要性如何进行进程等待waitwaitpidstatus多进程等待模型…...