线程池是怎么实现线程复用的,线程池里的线程复用实现原理简单描述

  线程池是怎么实现线程复用的,线程池里的线程复用实现原理简单描述

  00-1010前言源代码探索执行方法addWorker方法Worker类实现runnable接口重要属性构造方法Run方法执行过程总结

  00-1010我们都知道线程池可以帮助我们管理线程,重用线程来执行不同的任务。正常情况下,我们创建的线程会在任务完成后自我销毁,那么线程池是如何重用线程的呢?

  00-1010让我们从线程池ThreadPoolExecutor源代码开始了解一下。为了突出重点,下面的方法源代码为了逻辑清晰,过滤了一些无关的代码。

  00-1010先说线程池执行的execute方法!看一下该方法的源代码。

  public void execute(Runnable command){ if(command==null)throw new NullPointerException();int c=CTL . get();//1.如果小于核心线程数,则创建线程if(worker count of(c)core power size){ if(add worker(command,true))返回;c=CTL . get();} //2.当达到核心线程数且未超过队列限制时,添加到队列if(is running(c)work queue . offer(command)){ intre check=CTL . get();如果(!正在运行(重新检查)删除(命令))拒绝(命令);else if(worker count of(recheck)==0)add worker(null,false);} //3.当队列已满并且没有超过最大线程数时,如果(!idspninfopath _ NV),则创建线程else。AddWorker(command,false)) //4。达到最大线程数时,执行reject(命令);}我相信你已经了解了线程池执行的四个步骤。这里我们只看添加线程的方法,addWorker()

  

目录

私有布尔addWorker(Runnable firstTask,boolean core){ boolean worker started=false;boolean workerAdded=falseWorker w=null试试{//1。创建一个Worker,传入任务w=new Worker(first task);//2.取出执行任务的线程最终线程t=w.thread如果(t!=null){ final reentrant lock main lock=this . main lock;main lock . lock();请尝试{ int c=CTL . get();if(is running(c) (runStateLessThan(c,STOP)first task==null)){ if(t . getstate()!=线程。State.NEW)抛出新的IllegalThreadStateException();workers . add(w);workerAdded=trueint s=workers . size();如果最大池I

 

  ze) largestPoolSize = s; } } finally { mainLock.unlock(); } if (workerAdded) { //3.执行线程 t.start(); workerStarted = true; } } } finally { if (! workerStarted) addWorkerFailed(w); } return workerStarted; }参数解释:

  core:true表示添加的是核心线程,false表示添加的非核心线程

  这里大家只需要关心这3行加注释的代码就可以了

  就是Worker管理了创建的线程和这个线程执行的第一个任务,并且在addWorker方法中调用线程的start方法,开启线程执行了任务。下面我们看看Worker这个类

  

 

  

Worker类

 

  

实现了Runnable接口

Worker 是线程池ThreadPoolExecutor的内部类,实现了Runnable接口

 

  

private final class Worker extends AbstractQueuedSynchronizer implements Runnable

 

  

重要属性

他有两个核心关键的属性,即封装了线程池的线程和要执行的任务,达到了线程和任务解耦的目的。

 

  

final Thread thread;Runnable firstTask;

 

  

构造方法

addWorker方法会执行创建一个worker

 

  

w = new Worker(firstTask);

看一下Worker的构造方法

 

  

Worker(Runnable firstTask) {this.firstTask = firstTask; this.thread = getThreadFactory().newThread(this);}

可以看到 新创建的Worker本身也是一个Runnable,他的thread传的runnable任务就是worker本身

 

  在addWorker方法,最终会取到worker的thread属性,然后启动这个thread

  

w = new Worker(firstTask);final Thread t = w.thread;... ...t.start();

 

  

run方法

刚才介绍过,worker的thread的runnable参数传的就是worker本身,就是调的worker的run方法,现在我们来看最核心的worker的run方法

 

  

public void run() { runWorker(this);}

调的是ThreadPoolExecutor的runWorker方法

 

  

final void runWorker(Worker w) { Runnable task = w.firstTask; w.firstTask = null; try { while (task != null (task = getTask()) != null) { ... task.run(); ...

可以看到runWorker核心是一个while循环,执行了第一个task之后,就不停的从队列中取任务,直到没有任务了才会执行完,销毁线程

 

  

 

  

执行流程

execute方法调用addWorker方法,并且执行worker.thread.start()开启线程

 

   ——》worker.thread 执行worker本身的run方法(worker实现了Runnable接口)

   ——》执行ThreadPoolExecutor的runWorker方法,是个while循环,执行完worker本身的第一个任务之后,就不停从队列取任务,直到没有任务,执行完,退出循环,销毁

  

 

  

总结

线程池将线程和任务进行解耦,线程是线程,任务是任务,摆脱了之前通过 Thread 创建线程时的一个线程必须对应一个任务的限制。

 

  在线程池中,同一个线程可以从阻塞队列中不断获取新任务来执行,其核心原理在于线程池对 Thread 进行了封装,并不是每次执行任务都会调用 Thread.start() 来创建新线程,而是让每个线程去执行一个循环任务,在这个循环任务中不停的检查是否有任务需要被执行,如果有则直接执行,也就是调用任务中的 run 方法,将 run 方法当成一个普通的方法执行,通过这种方式将只使用固定的线程就将所有任务的 run 方法串联起来。

  本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注盛行IT的更多内容!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: