学习小记 -- 线程池的工作原理
线程池的五种状态:
Running:能接受新任务,可以处理已经添加的任务。
Shutdown:不接受新任务,可以处理已经添加的任务。
Stop:不接受新任务,不处理已经添加的任务,并且中断正在处理的任务。
Tidying:所有任务已经终止,ctl记录任务数为0。(ctl负责记录线程池的运行状态与活动线程数)
Terminated:线程池彻底终止。
工作原理
ThreadPoolExecutor执行execute()方法的示意图如下:
- 如果当前运行线程小于corePoolSize,则创建新线程来执行任务(执行这一步骤需要获取全局锁)。
- 如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。
- 如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(执行这一步骤需要获取全局锁)。
- 如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectExecutionHandler.rejectedExecution()方法。
ThreadPoolExecutor采取上述步骤,就是为了在执行execute()方法时,尽可能地避免获取全
局锁(这个是一个很严重的伸缩瓶颈)。在ThreadPoolExecutor完成预热之后(当前运行的线程数大于等于corePoolSize),几乎所有的execute()方法调用都是执行步骤2,而步骤2不需要获取全局锁。
代码片段如下:
public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();//如果线程数小于corePoolSize,则创建线程并执行当前任务if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}//如果任务可以成功排队,那么我们仍然需要再次检查我们是否应该添加一个线程(因为现有的在上次检查后就死了)if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (! isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}//如果线程池不处于运行中获无法放入队列,则创建一个线程执行任务else if (!addWorker(command, false))//抛出异常reject(command);}
int c = ctl.get();
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
将线程状态和活动线程数都记录在AtomicIneger里面,原子性保证并发安全。高3位存了线程状态。
线程池中的线程执行任务分两种情况:
- 在execute()方法中创建一个线程时,会让这个线程执行当前任务。
- 这个线程执行完上图1的任务后,会反复从BlockingQueue获取任务来执行。
向线程池提交任务
两种方式:execute()和submit()方法
execute()方法用于不需要返回值的任务,无法判断任务是否被线程池执行成功。
threadsPool.execute(new Runnable(){@Overridepublic void run{//DOTO}}
)
execute()方法输入的是一个Runnable类的实例。
submit()方法用于提交需要返回值的任务,返回的是一个future类型的对象,通过future对象可判断任务是否执行成功,并通过future.get()方法获取返回值,get()方法会阻塞当前线程直到任务完成。
Future<Object> future = execute.submit(harReturnValuetask);try{Object s = future.get();}catch(InterruptedException e){//处理中断异常}catch(ExecutionException e){//处理入法执行任务异常}finally{//关闭线程池execute.shutdown();}
关闭线程池
两种方法:shutdown()获shutdownNow()
原理:遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。
区别:
- shutdownNow首先将线程池的状态设置成STOP,然后尝试所有的正在执行或暂停任务的线程,并返回等待执行任务的列表。
- shutdown只是将线程池的状态设置成STOPDOWN状态,然后中断所有没有正在执行任务的线程。
参考 --《Java并发编程的艺术》方腾飞
学习小记 -- 线程池的工作原理相关推荐
- java 工作池_Java线程池的工作原理,好处和注意事项
线程池的工作原理 一个线程池管理了一组工作线程, 同时它还包括了一个用于放置等待执行 任务的任务队列(阻塞队列) . 一个线程池管理了一组工作线程, 同时它还包括了一个用于放置等待执行 任务的任务队列 ...
- java并发编程——线程池的工作原理与源码解读
2019独角兽企业重金招聘Python工程师标准>>> 线程池的简单介绍 基于多核CPU的发展,使得多线程开发日趋流行.然而线程的创建和销毁,都涉及到系统调用,比较消耗系统资源,所以 ...
- Java并发编程-线程池底层工作原理
线程池底层工作原理 1.线程池的底层工作流程 1.1.线程池的底层工作原理图 1.2.银行办理业务案例 1.3.线程池的底层工作流程总结 2.线程池用哪个?生产中如何设置合理参数 2.1.在工作中单一 ...
- 全面解读Java线程池的工作原理
目录 一.为什么引入线程池技术? 二.Executor框架 2.1 Runnable.Callable与Future接口 2.2 Executor接口 2.2.1 Executor 2.2.2 Exe ...
- 彻底搞懂Java线程池的工作原理
一.线程池的基础知识 创建线程需要占用一定的操作系统资源,在高并发情况下,频繁的创建和销毁线程会大量消耗CPU和内存资源,对程序性能造成很大的影响.为了避免这一问题,Java提供了线程池(通过线程复用 ...
- Java 线程池的工作原理
文章目录 概念 线程中的基本方法 线程复用 线程池的核心组件和核心类 线程池的工作原理 线程池中的workQueue任务队列 直接提交队列(SynchronousQueue) 有界任务队列(Array ...
- 一文读懂线程池的工作原理(故事白话文)
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 前言 本 ...
- java线程池的工作原理_JAVA线程池原理详解一
线程池的优点 1.线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用. 2.可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃. 线 ...
- 一文读懂线程池的工作原理
前言 本文以程序员做需求的例子,比喻线程池的工作过程.以故事白话的方式展开,跟大家阐述线程池工作原理,以方便大家更好理解线程池,谢谢阅读哈~ 什么是线程池? 什么是核心线程? 什么是阻塞队列? 什么是 ...
最新文章
- linux内核centos6.9,CentOS6.9手动编译并更新Kernel内核版本
- servlet中的session不一定会被创建
- Vim的一些使用技巧
- nodejs(三) --- nodejs进程与子进程
- eclipse导入项目Archive for required library cannot be read or is not a valid ZIP file
- JVM内存堆布局图解分析
- 使用条件注释完成浏览器兼容
- [译] APT分析报告:10.Lazarus以ThreatNeedle家族攻击工业事件还原(BMP图片隐藏RAT)
- 想要成为Java架构师不容放过的知识—Maven的版本发布
- Server.UrlEncode UrlDecode 动态绑定gridview列发送接收乱码的问题
- c++的头文件与源文件
- 2014_beijing_onsite
- html表单实验总结,HTML表单总结
- linux addr2line
- matlab中circle函数_JavaScript碎片——函数闭包(模拟面向对象)
- Storm入门(0)--流计算
- GridView导出Execl
- 2018最新圣思园JavaSE实地培训系列视频教程
- 数据连接池的工作原理
- iOS之推荐六款不错的 iOS 15 Safari 浏览器扩展