java 线程池 复用机制_理解线程池中线程的复用原理

本文深入解析Java线程池的线程复用机制。线程池通过创建Worker内部类并将其作为任务执行,利用while循环从任务队列workQueue获取任务,实现线程的复用。当任务队列为空时,线程可能因超时或被回收而退出。线程池的核心在于如何从任务队列中获取并执行任务,从而提高系统效率。
摘要由CSDN通过智能技术生成

fc1c44f9f4bbd07ccde024399b1ce001.png

线程的运行比较复杂,平常我们调用start(start0;)方法就完事了,啥时候执行run里面的代码?经过各种状态的转换获得cpu时间片,jvm就会帮我们执行run方法,执行完run方法这个线程自动消亡,遇到异常线程也会消亡,这就是一个线程的生命周期。

线程有两种实现方式,一种是继承Thread,重写run方法,一种是自己写一个Task实现runable接口重写run方法,他们的启动方式 分别是如下

//第一种方式,继承Thread,重写run方法后的启动

newMyThread().start();//第二种方式,将实现的runable接口的task作为参数传入Thread构造方法

new Thread(newRunnable() {

@Overridepublic voidrun(){

System.out.println("do something");

}

}).start();

jvm执行完run方法,就会执行退出方法,该退出方法在jvm内部用C++语言写的

voidJavaThread::exit(bool destroy_vm, ExitType exit_type) {//线程退出的方法

}

我们看这两种线程启动方式,感觉启动一次只能传一个任务进去。而且run方法又是由黑盒的jvm执行的,jvm执行完run方法就退出了,那线程池是怎么传多个任务进去的?怎么控制run方法一直执行的?

这一系列疑问,要进入线程池源码才能略知一二

源码实在太复杂了,我们从前文的铺垫开始,以正常人的思路,首先找到我们的主角---线程

1,线程池中的线程在哪?

当我们没有将线程工厂传入的时候使用的是默认的线程工厂

//1,ThreadPoolExecutor的构造方法众多,但都指向一个,那就是如下

this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,

Executors.defaultThreadFactory(), handler);

​//2,将Executors.defaultThreadFactory()进入会发现默认线程工厂

public staticThreadFactory defaultThreadFactory() {return newDefaultThreadFactory();

}//3,在哪触发产生线程?在如下构造方法里,//产生线程的s时候将这个内部类this本身传递进去

Worker(Runnable firstTask) {

setState(-1); //inhibit interrupts until runWorker

this.firstTask =firstTask;this.thread = getThreadFactory().newThread(this);

}//4,进入产生线程的方法

publicThread newThread(Runnable r) {

Thread t= new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0);

...//其他代码

returnt;

}

好了我们的线程主角已经登场,但是他的登场并没有多高大上,而是寄人篱下在一个名叫Worker的内部类里

这个意思是只要 new Worker(Runnable firstTask),就会产生一个线程,并且产生线程的时候将这个内部类本身this传入进去当task。

这似乎跟我们前文讲的差不多,new一个线程就放一个task,说好的线程复用呢?好了主角线程有了,我们的task也有了,我们再找找start方法

//线程启动的时候

private boolean addWorker(Runnable firstTask, booleancore) {

w= newWorker(firstTask);final Thread t =w.thread;

...//代码

t.start();

...//代码

}

线程是启动了,别忘了,线程启动的时候我们将内部类worker对象传入进去了,内部类Worker是实现了runable接口的,jvm执行run方法的时候就会执行Worker中的run方法

//1,这是Work中的一个方法,线程启动的时候jvm会执行它,

public voidrun() {

runWorker(this);

}

​//2,继续看里面的runWorker(this);很显然this是内部类Work对象本身

final voidrunWorker(Worker w) {

Thread wt=Thread.currentThread();

Runnable task=w.firstTask;

w.firstTask= null;

../代码try{while (task != null || (task = getTask()) != null) {try{

../代码

task.run();

}catch(){

../代码

}finally{

../代码

}

}

../代码

}finally{

../代码

}

}

很显然这个runWorker很不得了,里面一个大大的while循环,当我们的task不为空的时候它就永远在循环,并且会源源不断的从getTask()获取新的任务,继续看getTask()方法

//很显然这个方法是从队列中获取任务workQueue

privateRunnable getTask() {

...//代码//Are workers subject to culling?

boolean timed = allowCoreThreadTimeOut || wc >corePoolSize;if ((wc > maximumPoolSize || (timed &&timedOut))&& (wc > 1 ||workQueue.isEmpty())) {if(compareAndDecrementWorkerCount(c))return null;continue;

}try{

Runnable r= timed ?workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :

workQueue.take();if (r != null)returnr;

timedOut= true;

}catch(InterruptedException retry) {

timedOut= false;

}

}

}

很显然,getTask()方法里面有个三元表达式,当条件为真时从任务对列workQueue.take()里面获取要执行得任务;

讲到这里线程复用的流程就讲完了,最核心的一点是,新建一个Worker内部类就会建一个线程,并且会把这个内部类本身传进去当作任务去执行,这个内部类的run方法里实现了一个while循环,当任务队列没有任务时结束这个循环,则这个线程就结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您简单介绍一下Java线程池实现原理Java线程池是一种多线程处理的方式,它可以有效地控制线程的创建、销毁和复用线程池包含一个线程队列,用于存储等待执行的任务,以及一组可用的线程,用于处理这些任务。 线程池的核心原理是将线程的创建和销毁分离开来,通过重复利用已有的线程,避免了频繁创建和销毁线程所带来的性能开销。 在Java线程池实现主要依赖于以下三个核心组件: 1. 线程池管理器(ThreadPoolExecutor):负责管理线程池的所有线程,包括线程的创建、销毁和调度等操作。 2. 线程池工厂(ThreadFactory):用于创建新的线程,可以自定义线程的名称、优先级、是否为守护线程等属性。 3. 任务队列(BlockingQueue):用于存储等待执行的任务,包括有界队列(ArrayBlockingQueue)和无界队列(LinkedBlockingQueue)两种。 当我们向线程池提交任务时,线程池会根据一定的策略从任务队列选择一个任务,然后将其分配给线程池的一个可用线程进行处理。如果线程池没有可用的线程,那么任务会被暂时放入任务队列等待处理。 当线程池线程完成任务后,它们并不会被立即销毁,而是将其返回到线程池等待下一个任务的到来。这样,线程池就可以继续重复利用这些线程,避免了频繁创建和销毁线程所带来的性能开销。 希望以上内容对您有所帮助,谢谢!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值