一个线程在运行结束后, 是不能再次调用start() 方法启动的.
那JDK中的线程池是如何做到线程回收以及复用的呢?
复用原理
复用原理很简单, 就是生产者消费模式
将提交的线程任务写入任务队列, 线程池中的一个线程不断的从任务队列中拿出任务并执行.
代码语言:javascript复制
代码语言:javascript复制BlockingQueueworkQueue = new ArrayBlockingQueue(10);
for(;;){
Runnable r = workQueue.take();
r.run();
}
线程复用
在线程池(ThreadPoolExecutor)中, 线程复用过程也是类似的.
1. 向线程池提交任务之后,
如果当前执行中的线程数是否小于核心线程数(corePoolSize), 则执行addWorker()方法, 直接执行任务;
否则, 将任务添加到任务队列(workQueue)中.
代码语言:javascript复制
代码语言:javascript复制public void execute(Runnable command) {
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
}
if (isRunning(c) && workQueue.offer(command)) {
}
else if (!addWorker(command, false))
reject(command);
}
2. 执行任务时, 首先会创建一个封装了任务和线程信息的Worker对象, 启动并执行worker.
代码语言:javascript复制
代码语言:javascript复制private boolean addWorker(Runnable firstTask, boolean core) {
w = new Worker(firstTask);
final Thread t = w.thread;
t.start();
}
Worker对象封装任务与线程.
代码语言:javascript复制
代码语言:javascript复制private final class Worker extends AbstractQueuedSynchronizer
implements Runnable {
Runnable firstTask;
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}}
3. worker线程启动后, 会执行runWorker()方法,
会根据条件worker.task != null 优先执行提交的任务;
后续执行时, 会根据(task = getTask()), 从任务队列(workQueue)中取出task, 并继续执行.
代码语言:javascript复制
代码语言:javascript复制final void runWorker(Worker w) {Runnable task = w.firstTask;
while (task != null || (task = getTask()) != null) {
task.run();
}
}
4. 从任务队列(workQueue)中取出task
代码语言:javascript复制
代码语言:javascript复制private Runnable getTask() {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
return r;
}
处理流程如下: