Update Java 并发.md

补充新的关于线程池的说明
This commit is contained in:
HuaHero 2023-11-09 15:30:13 +08:00 committed by GitHub
parent 37db7c6035
commit 251401eb61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -149,12 +149,12 @@ public static void main(String[] args) {
### Executor
Executor 管理多个异步任务的执行,而无需程序员显式地管理线程的生命周期。这里的异步是指多个任务的执行互不干扰,不需要进行同步操作。
Executors 管理多个异步任务的执行,而无需程序员显式地管理线程的生命周期。这里的异步是指多个任务的执行互不干扰,不需要进行同步操作。
主要有三种 Executor
- CachedThreadPool一个任务创建一个线程
- FixedThreadPool所有任务只能使用固定大小的线程
- FixedThreadPool所有任务只能使用固定大小的线程,但是线程池默认使用了无界队列
- SingleThreadExecutor相当于大小为 1 的 FixedThreadPool。
```java
@ -210,6 +210,22 @@ public void run() {
}
```
**关于线程池**
【线程池的意义】
线程池可以有效地管理线程:它可以**管理线程的数量**,可以避免无节制的创建线程,导致超出系统负荷直至崩溃。它还可以**让线程复用**,可以大大地减少创建和销毁线程所带来的开销。
【**线程池的核心参数**】 线程池需要依赖一些参数来控制任务的执行流程,其中最重要的参数有corePoolSize核心线程数、workQueue等待队列、maxinumPoolSize最大线程数、handler拒绝策略、keepAliveTime空闲线程存活时间
【线程池的运作步骤】
当我们向线程池提交一个任务之后,线程池按照如下步骤处理这个任务:
1. 判断线程数是否达到corePoolSize,若没有则新建线程执行该任务,否则进入下一步。
2. 判断等待队列是否已满,若没有则将任务放入等待队列,否则进入下一步。
3. 判断线程数是否达到maxinumPoolSize,如果没有则新建线程执行任务,否则进入下一步。
4. 采用初始化线程池时指定的拒绝策略,拒绝执行该任务。
5. 新建的线程处理完当前任务后,不会立刻关闭,而是继续处理等待队列中的任务。如果线程的空闲时间达到了keepAliveTime,则线程池会销毁一部分线程,将线程数量收缩至corePoolSize。 第2步中的队列可以有界也可以无界。若指定了无界的队列,则线程池永远无法进入第3步,相当于废弃了maxinumPoolSize参数。这种用法是十分危险的,如果任务在队列中产生大量的堆积,就很容易造成内存溢出。
【线程池创建工具--建议用**ThreadPoolExecutor**】
JDK为我们提供了一个名为Executors的线程池的创建工具,该工具创建出来的就是带有无界队列的线程池,所以一般在工作中我们是不建议使用这个类来创建线程池的。 第4步中的拒绝策略主要有4个让调用者自己执行任务、直接抛出异常、丢弃任务不做任何处理、删除队列中最老的任务并把当前任务加入队列。这4个拒绝策略分别对应着RejectedExecutionHandler接口的4个实现类,我们也可以基于这个接口实现自己的拒绝策略。 在Java中,线程池的实际类型为ThreadPoolExecutor,它提供了线程池的常规用法。该类还有一个子类,名为ScheduledThreadPoolExecutor,它对定时任务提供了支持。在子类中,我们可以周期性地重复执行某个任务,也可以延迟若干时间再执行某个任务。
在Java中正常创建线程池应该使用ThreadPoolExecutor类。虽然Executors类可以方便地创建线程池但它使用的默认参数可能不适合所有情况。例如Executors.newFixedThreadPool方法创建的线程池默认使用无界队列可能会导致内存溢出。此外Executors类隐藏了线程池的细节使得无法对其进行更灵活的配置和优化。因此建议使用ThreadPoolExecutor类手动创建线程池并根据具体情况进行参数配置。
【线程池的生命周期状态】 线程池的生命周期包含5个状态RUNNING、SHUTDOWN、STOP、TIDING、TERMINATED。这5种状态的状态值分别是-1、0、1、2、3。在线程池的生命周期中,它的状态只能由小到大迁移,是不可逆的。 1. RUNNING表示线程池正在运行。 2. SHUTDOWN执行shutdown()时进入该状态,此时队列不会清空,线程池会等待任务执行完毕。 3. STOP执行shutdownNow()时进入该状态,此时现线程池会清空队列,不再等待任务的执行。 4. TIDING当线程池及队列为空时进入该状态,此时线程池会执行钩子函数,目前该函数是一个空的实现。 5. TERMINATED钩子函数执行完毕后,线程进入该状态,表示线程池已经死亡。
来自https://www.nowcoder.com/exam/interview/75826387/test?paperId=50270024
## 三、中断
一个线程执行完毕之后会自动结束,如果在运行过程中发生异常也会提前结束。