线程池的五种状态:

Running:能接受新任务,可以处理已经添加的任务。

Shutdown:不接受新任务,可以处理已经添加的任务。

Stop:不接受新任务,不处理已经添加的任务,并且中断正在处理的任务。

Tidying:所有任务已经终止,ctl记录任务数为0。(ctl负责记录线程池的运行状态与活动线程数)

Terminated:线程池彻底终止。

工作原理

ThreadPoolExecutor执行execute()方法的示意图如下:

  1. 如果当前运行线程小于corePoolSize,则创建新线程来执行任务(执行这一步骤需要获取全局锁)。
  2. 如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。
  3. 如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(执行这一步骤需要获取全局锁)。
  4. 如果创建新线程将使当前运行的线程超出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位存了线程状态。 

线程池中的线程执行任务分两种情况:

  1. 在execute()方法中创建一个线程时,会让这个线程执行当前任务。
  2. 这个线程执行完上图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方法来中断线程,所以无法响应中断的任务可能永远无法终止。

区别:

  1. shutdownNow首先将线程池的状态设置成STOP,然后尝试所有的正在执行或暂停任务的线程,并返回等待执行任务的列表。
  2. shutdown只是将线程池的状态设置成STOPDOWN状态,然后中断所有没有正在执行任务的线程。

参考 --《Java并发编程的艺术》方腾飞

学习小记 -- 线程池的工作原理相关推荐

  1. java 工作池_Java线程池的工作原理,好处和注意事项

    线程池的工作原理 一个线程池管理了一组工作线程, 同时它还包括了一个用于放置等待执行 任务的任务队列(阻塞队列) . 一个线程池管理了一组工作线程, 同时它还包括了一个用于放置等待执行 任务的任务队列 ...

  2. java并发编程——线程池的工作原理与源码解读

    2019独角兽企业重金招聘Python工程师标准>>> 线程池的简单介绍 基于多核CPU的发展,使得多线程开发日趋流行.然而线程的创建和销毁,都涉及到系统调用,比较消耗系统资源,所以 ...

  3. Java并发编程-线程池底层工作原理

    线程池底层工作原理 1.线程池的底层工作流程 1.1.线程池的底层工作原理图 1.2.银行办理业务案例 1.3.线程池的底层工作流程总结 2.线程池用哪个?生产中如何设置合理参数 2.1.在工作中单一 ...

  4. 全面解读Java线程池的工作原理

    目录 一.为什么引入线程池技术? 二.Executor框架 2.1 Runnable.Callable与Future接口 2.2 Executor接口 2.2.1 Executor 2.2.2 Exe ...

  5. 彻底搞懂Java线程池的工作原理

    一.线程池的基础知识 创建线程需要占用一定的操作系统资源,在高并发情况下,频繁的创建和销毁线程会大量消耗CPU和内存资源,对程序性能造成很大的影响.为了避免这一问题,Java提供了线程池(通过线程复用 ...

  6. Java 线程池的工作原理

    文章目录 概念 线程中的基本方法 线程复用 线程池的核心组件和核心类 线程池的工作原理 线程池中的workQueue任务队列 直接提交队列(SynchronousQueue) 有界任务队列(Array ...

  7. 一文读懂线程池的工作原理(故事白话文)

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 前言 本 ...

  8. java线程池的工作原理_JAVA线程池原理详解一

    线程池的优点 1.线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用. 2.可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃. 线 ...

  9. 一文读懂线程池的工作原理

    前言 本文以程序员做需求的例子,比喻线程池的工作过程.以故事白话的方式展开,跟大家阐述线程池工作原理,以方便大家更好理解线程池,谢谢阅读哈~ 什么是线程池? 什么是核心线程? 什么是阻塞队列? 什么是 ...

最新文章

  1. linux内核centos6.9,CentOS6.9手动编译并更新Kernel内核版本
  2. servlet中的session不一定会被创建
  3. Vim的一些使用技巧
  4. nodejs(三) --- nodejs进程与子进程
  5. eclipse导入项目Archive for required library cannot be read or is not a valid ZIP file
  6. JVM内存堆布局图解分析
  7. 使用条件注释完成浏览器兼容
  8. [译] APT分析报告:10.Lazarus以ThreatNeedle家族攻击工业事件还原(BMP图片隐藏RAT)
  9. 想要成为Java架构师不容放过的知识—Maven的版本发布
  10. Server.UrlEncode UrlDecode 动态绑定gridview列发送接收乱码的问题
  11. c++的头文件与源文件
  12. 2014_beijing_onsite
  13. html表单实验总结,HTML表单总结
  14. linux addr2line
  15. matlab中circle函数_JavaScript碎片——函数闭包(模拟面向对象)
  16. Storm入门(0)--流计算
  17. GridView导出Execl
  18. 2018最新圣思园JavaSE实地培训系列视频教程
  19. 数据连接池的工作原理
  20. iOS之推荐六款不错的 iOS 15 Safari 浏览器扩展

热门文章

  1. Python文件的读写以及操作excel
  2. 喜茶多肉瓜瓜 | 埃德珈奶茶饮品培训,饮品配方做法制作教程
  3. 2017 蓝桥杯决赛 C++B(2)瓷砖样式 dfs + hash去重
  4. Excel 中的一些计数及求和的函数
  5. 2022.10.14每日刷题打卡
  6. 无法连接虚拟设备 sata0:1,因为主机上没有相对应的设备——解决方案
  7. ipad协议8033
  8. 什么样的打码网站算正规的打码网站
  9. python实操实例100例_趣学Python算法100例
  10. 微信浏览器中进行支付宝支付