Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行的程序都可以使用线程池。

合理使用线程池能带来三个好处:

  1. 降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗;
  2. 提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行;
  3. 提高线程的可管理性,线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配,调优和监控。

线程池的实现原理

当提交一个任务时,线程池的处理流程如下

很清晰的一幅图,简洁明了

  1. 我们提交一个任务到线程池时,线程池首先判断当前核心线程池是否已满,如果没有满的话,那么就直接创建一个新的线程来执行任务;如果核心线程池已满的话那么就去判断队列是否已满;
  2. 如果工作队列没有满的话,那么就将这个任务存储到工作队列中进行等待;如果没满的话,那么就去判断线程池是否已满;
  3. 如果线程池没有满的话,同样创建一个新的线程去执行任务;相反,如果线程池满的话那么就去按照饱和策略处理无法执行的任务。

ThreadPoolExcutor执行excute()方法的示意图

ThreadPoolExcute执行excute方法分下面四种情况:

  1. 如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步需要获取全局锁);
  2. 如果运行的线程等于corePoolSize,则将任务加入BlockingQueue;
  3. 如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(同上,执行这一步需要获取全局锁);
  4. 如果创建新线程将使当前运行的线程 超出maximumPoolSize,任务将被拒绝,并且调用RejectedExecutionHandler.rejectedExecution()方法

ThreadPoolExecutor采取上述步骤的总体设计思路,是为了在执行execute()方法时,尽可能地避免获取全局锁(那将回事一个严重的可伸缩瓶颈)。在ThreadPoolExecutor完成预热之后(当前运行的线程数大于等于corePoolSize),几乎所有的execute()方法调用都是执行步骤2,而步骤2不需要获取全局锁。

源码分析

  public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();/***  如果运行的线程小于corePoolSize,则尝试用给定的命令作为第一个任务启动一个新线程。*  对addWorker的调用原子性地检查runState和workerCount,因此可以通过返回false来防止错误警报,因为错误警报会在不应该添加线程的时候添加线程。*/if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}// 线程池处于RUNNING状态,并将任务放入workQueue队列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);}

工作线程:线程池创建线程时,会将线程粉装成工作线程Worker,Worker在执行完任务后,还会循环获取工作队列里的任务来执行。我们可以从Worker类的run()方法里看到。

public void run(){try{Runnable task = firstTask;firstTask = null;while(task != null || (task = getTask()) != null){runTask(task);task = null;}} finally {workerDone(this);}
}

ThreadPoolExecutor中线程执行任务的示意图如图

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

  1. 在execute()方法中创建一个线程时,会让这个线程执行当前任务;
  2. 这个线程执行完图中1的任务后,会反复从BlockingQueue获取任务来执行。

————《Java并发编程的艺术》 方腾飞  魏鹏 程晓明  著

【多线程和并发】Java中的线程池的实现原理相关推荐

  1. 四十七、面试前,必须搞懂Java中的线程池ThreadPoolExecutor(上篇)

    @Author:Runsen @Date:2020/6/9 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...

  2. 万字图文 | 学会Java中的线程池,这一篇也许就够了!

    来源:一枝花算不算浪漫 线程池原理思维导图.png 前言 Java中的线程池已经不是什么神秘的技术了,相信在看的读者在项目中也都有使用过.关于线程池的文章也是数不胜数,我们站在巨人的肩膀上来再次梳理一 ...

  3. JAVA中创建线程池的五种方法及比较

    之前写过JAVA中创建线程的三种方法及比较.这次来说说线程池. JAVA中创建线程池主要有两类方法,一类是通过Executors工厂类提供的方法,该类提供了4种不同的线程池可供使用.另一类是通过Thr ...

  4. 多线程线程池的实现java_如何在Java中实现线程池

    多线程线程池的实现java 线程是独立程序的执行路径. 在java中,每个线程都扩展java.lang.Thread类或实现java.lang.Runnable. 多线程是指在一个任务中同时执行两个或 ...

  5. 如何在Java中实现线程池

    线程是独立程序的执行路径. 在java中,每个线程都扩展java.lang.Thread类或实现java.lang.Runnable. 多线程是指在一个任务中同时执行两个或多个线程.在多线程中,每个任 ...

  6. java中的线程池有哪些,分别有什么作用?

    阅读完本篇文章会知道如下三点: 1.进程-线程简单介绍 2.java的线程池是什么,有哪些类型,作用分别是什么 3.使用线程池的优点 1.进程-线程的简单介绍 进程 什么是进程呢? 进程是计算机中的程 ...

  7. Java多线程编程(1)--Java中的线程

    一.程序.进程和线程   程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码.它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文 ...

  8. 深入理解java中的线程池

    线程池中各个参数的含义 corePoolSize: 核心池的大小,这个参数跟线程池的实现原理有非常大的关系.**在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行 ...

  9. 【高并发】java中的线程池 ThreadPoolExecutor

    文章目录 1.概述 1.2 参数顺序 2. 案例 2.1 线程池使用的简单示例 2.2 线程池使用的简单示例 3. 线程池中常见5种工作队列 3.1 SynchronousQueue队列的线程池 3. ...

最新文章

  1. 突破:量子计算机首次实现简化逻辑门
  2. C语言函数调用过程的汇编分析(停更)
  3. ubuntu18.04利用fdisk找到磁盘空闲区,新建分区,挂载
  4. ajax后台重定向会返回什么_跳转,AJAX返回和重定向
  5. C++ 中export 关键字的尴尬处境
  6. SAP MM ME51N 创建采购申请单据时候永远取物料主数据基本计量单位
  7. SQL Server 中系统表的作用
  8. Mac如何打开CAJ格式的文件?
  9. ESP8266(3)
  10. 二进制 八进制 十进制 十六进制
  11. 嵌入式C语言static关键字
  12. 存在感应雷达模块,LED灯感应控制,微波雷达技术应用
  13. 使用ingress暴露kubernetes集群内部的pod服务
  14. 高速串行总线设计基础(七)揭秘SERDES高速面纱之时钟校正与通道绑定技术
  15. chromecast网络访问受限
  16. 向阅读致敬!微信读书产品设计策略推导
  17. docker容器虚拟技术
  18. 如何提升自身能力?不再平庸
  19. 朴实无华,图解快排,多语言实现。(PS:还有宝藏资料)
  20. HFM-合并应用程序迁移(COPY APPLICATION)

热门文章

  1. python线上培训班5月是淡季
  2. 基于SSM的医院门诊预约挂号系统的设计与实现(文末附源码、论文)
  3. antd Upload 上传多张图片 react hooks
  4. 文科转码人第一个项目记录——B站动力节点《米米商城》
  5. 数据分析中相关性分析相关的概念
  6. buuctf 乌镇峰会种图 1
  7. 【Parallax Animation】实现知乎 Android 客户端启动页视差滚动效果
  8. 2015 年全国大学生电子设计竞赛(本科组)试题目录★√
  9. 如何DOS命令进入D盘文件夹
  10. WSL2 如何进入C盘或D盘目录