Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >线程池如何做到线程复用的

线程池如何做到线程复用的

作者头像
一个架构师
发布于 2022-06-20 12:04:41
发布于 2022-06-20 12:04:41
76800
代码可运行
举报
运行总次数:0
代码可运行

一个线程在运行结束后, 是不能再次调用start() 方法启动的.

那JDK中的线程池是如何做到线程回收以及复用的呢?

复用原理

复用原理很简单, 就是生产者消费模式

将提交的线程任务写入任务队列, 线程池中的一个线程不断的从任务队列中拿出任务并执行.

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
BlockingQueueworkQueue = new ArrayBlockingQueue(10);
for(;;){
    Runnable r =  workQueue.take();
    r.run();
}

线程复用

在线程池(ThreadPoolExecutor)中, 线程复用过程也是类似的.

1. 向线程池提交任务之后,

如果当前执行中的线程数是否小于核心线程数(corePoolSize), 则执行addWorker()方法, 直接执行任务;

否则, 将任务添加到任务队列(workQueue)中.

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private boolean addWorker(Runnable firstTask, boolean core) {
       w = new Worker(firstTask);        
       final Thread t = w.thread;
       t.start(); 
}

Worker对象封装任务与线程.

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
final void runWorker(Worker w) {Runnable task = w.firstTask;
        while (task != null || (task = getTask()) != null) {
          task.run();
        }
}

4. 从任务队列(workQueue)中取出task

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private Runnable getTask() {
     Runnable r = timed ?
        workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
        workQueue.take();
        return r;
 }

处理流程如下:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 从码农的全世界路过 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
谈谈ThreadPoolExecutor线程池
线程池,凡是学过java的同学都不陌生,一两行简单的代码就能实现并发编程。但java.util.concurrent.ThreadPoolExecutor的源码读起来却是很绕,今天,就让我们来深入了解一下线程池吧。
zhangheng
2020/04/29
4810
从使用到原理学习Java线程池
在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。
Java团长
2018/07/23
3680
从使用到原理学习Java线程池
Java源码之ThreadPoolExecutor
“ ThreadPoolExecutor类是线程池的基础,线程池的目的是为了减少了每个任务调用的开销,在拥有大量异步任务时可以增强的性能,并且还可以提供绑定和管理资源的方法”
每天学Java
2020/06/02
4920
如何优雅的使用线程池!!!
在前面使用的例子用,我们已经使用过线程池,基本上就是初始化线程池实例之后,把任务丢进去,等待调度执行就可以了,使用起来非常简单、方便。虽然使用很简单,但线程池涉及到的知识点非常多。需要分析其实现。
用户2242639
2021/06/29
1.7K0
线程池实现原理-2
仔细理解一下这段代码,其实就能理解,当线程池处于RUNNING 接受新任务,并且处理进入队列的任务,处于SHUTDOWN 不接受新任务,处理进入队列的任务,剩余状态都不会处理任务,上面代码中的注释有详细解释
Java识堂
2019/08/13
6720
Java之线程池源码浅析
线程是稀缺资源,如果被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池对线程进行统一分配、调优和监控,有以下好处:重用存在的线程、可有效控制最大并发线程数
笔头
2022/01/19
2770
手写线程池,对照学习ThreadPoolExecutor线程池实现原理!
作者:小傅哥 博客:https://bugstack.cn Github:https://github.com/fuzhengwei/CodeGuide/wiki
huofo
2022/03/18
4000
手写线程池,对照学习ThreadPoolExecutor线程池实现原理!
Java 线程池中的线程复用是如何实现的?
那么就来和大家探讨下这个问题,在线程池中,线程会从 workQueue 中读取任务来执行,最小的执行单位就是 Worker,Worker 实现了 Runnable 接口,重写了 run 方法,这个 run 方法是让每个线程去执行一个循环,在这个循环代码中,去判断是否有任务待执行,若有则直接去执行这个任务,因此线程数不会增加。
用户1516716
2020/06/29
4.2K0
Java 线程池中的线程复用是如何实现的?
通过ThreadPoolExecutor源码分析线程池实现原理
线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性。使用线程池可以重复利用已创建的线程降低线程创建和销毁带来的消耗,随之即可提高响应速度(当一个任务到达时,不需要重新创建线程来为之服务,重用已有线程),还可以通过线程池控制线程资源统一分配和监控等。
GreizLiao
2020/03/17
3460
通过ThreadPoolExecutor源码分析线程池实现原理
Java-线程池动态修改大小
corePoolSize:核心线程数大小,不管它们创建以后是不是空闲的。线程池需要保持 corePoolSize 数量的线程,除非设置了 allowCoreThreadTimeOut;
茶半香初
2021/11/26
2.8K0
Java-线程池动态修改大小
Java线程池深度揭秘
Executor 是一个接口(主要用于定义规范),定义了 execute 方法,用于接收 Runnable 对象。
一猿小讲
2020/08/10
3400
Java线程池深度揭秘
透彻Java线程池的实现原理
其实java线程池的实现原理很简单,说白了就是一个线程集合workerSet和一个阻塞队列workQueue。当用户向线程池提交一个任务(也就是线程)时,线程池会先将任务放入workQueue中。
挨踢小子部落阁
2023/03/15
3120
透彻Java线程池的实现原理
线程池源码解读
线程池的在 Java并发中使用最多的一种手段,也是性能和易用性相对来说比较均衡的方式,下面我们就一起探索先线程池的原理。
付威
2023/10/17
1650
线程池源码解读
Java 线程线程池初探
所谓线程池,就是将多个线程放在一个池子里面(所谓池化技术),然后需要线程的时候不是创建一个线程,而是从线程池里面获取一个可用的线程,然后执行我们的任务。线程池的关键在于它为我们管理了多个线程,我们不需要关心如何创建线程,我们只需要关系我们的核心业务,然后需要线程来执行任务的时候从线程池中获取线程。任务执行完之后线程不会被销毁,而是会被重新放到池子里面,等待机会去执行任务。
纯洁的微笑
2019/09/05
8790
Java 线程线程池初探
从源码的角度解析线程池运行原理
在讲解完线程池的构造参数和一些不常用的设置之后,有些同学还是想继续深入地了解线程池的原理,所以这篇文章科代表会带大家深入源码,从底层吃透线程池的运行原理。
纯洁的微笑
2019/06/14
5870
从源码的角度解析线程池运行原理
相关推荐
谈谈ThreadPoolExecutor线程池
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验