ThreadPoolExecutor中的任务提交和线程池中的线程复用
程序员文章站
2022-06-20 20:26:00
...
execute()方法
execute()传一个Runnable接口,但是我们调用的时候传的是一个实现了Runnable接口的类。多态特性由多态可知,子类对象赋给父类对象时其子类的run方法就传给了父类对象的run方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//如果当前线程数小于,coresize,那么我们就要生成一个新的Worker
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//如果当前线程数大于coresize,则放到阻塞队列中
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
//特殊的线程池,cached
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
1)线程池有一个预热功能,当线程数小于coresize时,此时addWorker中会生成新的Worker,Worker的构造函数如下
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
//传来的Runnable接口
this.firstTask = firstTask;
//通过线程工厂,把this(当前Worker)指针传给Thread,
//newThread()方法的参数是Runnable接口,Worker实现了Runnable接口,因此把Worker的run方法传过去了,多态的用法
this.thread = getThreadFactory().newThread(this);
}
2)当addWorker添加成功是,就会调用Worker对象中的thread属性的start()方法
w = new Worker(firstTask);
final Thread t = w.thread;
t.start();
3)此时,start方法会调用worker的run方法,即runWorker()方法
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
....
}
当task不为空,即说明有任务过来
当task为空,task=getTask()不为空,说明没有任务过来,从阻塞队列中能获取到任务
getTask方法
for (;;) {
....
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
....
}
线程池总结
1)当刚提交任务的时候,如果小于coresize,就生成新的Worker()即Thread。
2)如果提交时,大于了coresize,那么就放入WorkQueue的阻塞队列中。当阻塞队列有元素时,那么之前生成的线程就可以进行复用了
线程复用情形
假设有一个线程池的coresize为5,那么假设5个线程工作状态,此时有一个任务来了。则5个线程工作完成后,它们中只有一个线程能够获取这个任务,其余线程由于在getTask()中没有抢到任务,因此getTask就会一直处于自旋且不会返回。这样就完成了线程的复用。