也来分析下Java 线程池(ThreadPoolExecutor)的原理

本文详细介绍了Java线程池的工作原理及其实现机制,包括线程池的创建、任务提交、线程池的关闭等操作。同时,还探讨了核心线程池的创建时机与维护方式,以及线程池如何通过中断线程来停止。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先提几个问题:
1.线程池的工作原理是啥?
2.核心线程池是一开始时就创建够吗?空闲时核心线程池也一直维持不变吗?
3.线程池是如何被停止的?

如果你都能非常自信地回答出来,那后面的内容可以不用看了。


参考文章:
《Java 线程池(ThreadPoolExecutor)原理分析与使用》

一、线程池的使用
1.创建线程池:

通过new创建,构造函数为:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)

2.提交任务:

public void execute(Runnable command)

3.关闭线程池:

1.public void shutdown()
2.public List shutdownNow()
两个方法的区别:
shutdown方法是尝试将所有空闲线程intrupt掉;而shutdownNow是将所有活动中的线程以及空闲线程都intrupt掉。

二、实现原理

这里写图片描述

三、原理分析

1.用来充当线程池的是一个数组:private final HashSet workers;
2.每个提交的任务都是一个Runnable,进入线程池后,会被包装成为一个 Worker;
3.Worker类是个内部类,自身实现了Runnable接口。它有两个成员变量:

Thread thread,
Runnable firstTask,

Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
}

/** Delegates main run loop to outer runWorker. */
public void run() {
    runWorker(this);
}

从代码里可以看出,Worker在创建线程Thread时,用的是自身;而不是原始的任务firstTask,这样一来,就得到了干预线程执行的机会。
4.在runWorker方法的主要代码如下:

task = w.firstTask;
try{
    while (task != null || (task = getTask()) != null){
        task.run();
    }
} finally {
    processWorkerExit(w, completedAbruptly);
}

5.在addWorker方法中,做了两件事:创建线程并执行;即:
1.根据Runnable创建Worker对象;
2.将Worker对象存入数组workers中;
3.执行Worker对象里的thread;

6.根据线程的实现,我们知道t.start()的执行最终会调用Runnable里的run方法;由此可知在addWorker方法执行线程,最终会走到runWorker方法里来;
7.从runWorker方法的实现可以看到,每个入参Worker中的线程在完成自身的firstTask任务之后,还要继续去完成队列中的任务;
8.在runWorker方法中,当执行完所有的任务或者当执行完一个任务后发现线程已被中断,则会跳出循环,调用processWorkerExit方法来自动终结自己。
9.processWorkerExit方法里主要做了两件事:
1.将入参worker从数组workers里删除掉;
2.根据布尔值allowCoreThreadTimeOut来决定是否补充新的Worker进数组workers,方法为:

addWorker(null, false);

意思为只新增线程,无初始的任务。

回答前面的问题

1.线程池的工作原理是啥?
答:见原理图,先coresize,再queue队列,再maxsize,最后RejectedExecutionHandler。

2.核心线程池是一开始时就创建够吗?空闲时核心线程池也一直维持不变吗?
答:不是的,线程池是逐一增加至核心线程数的。不过可以通过executor提供的一些方法来直接将线程池预热至核心线程数。如方法:

public int prestartAllCoreThreads()

空闲时会根据allowCoreThreadTimeOut的值来决定是否要维持核心线程数的线程。该值默认是false,就是要维持核心线程池。可以通过方法来修改该布尔值。

3.线程池是如何被停止的?
答:通过shutdown或者shutdownNow方法来停止线程池。在这两个方法中,都是通过循环将works里每个work的线程进行Thread.interrupt()调用,给线程设置一个的停止标志。线程在自己的run方法中可以通过循环检查.interrupted()方法是否为真,来结束自己。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值