ThreadPoolExecutor
1.什么是线程池?
(首先要理解什么是线程)
线程池,thread pool,是一种线程使用模式,线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。

  • 通俗来说,就是可管理和维护以及分配线程的“池子”。

2.为什么使用线程池?
为了减少创建和销毁线程的次数,让每个线程都可以多次的使用,可以根据系统情况调整线程的数量,防止消耗过多内存。在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,使用线程池就可以优化。
线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使用应用程序响应更快。另外,通过适当的调整线程中的线程数目可以防止出现资源不足的情况。

  • 通俗来说,就是为了优化线程的内存开销。

3.线程池的核心参数

public ThreadPoolExecutor(int corePoolSize,//核心线程数int maximumPoolSize,//最大线程数long keepAliveTime,//线程空闲时间TimeUnit unit,//时间单位BlockingQueue<Runnable> workQueue,//任务队列ThreadFactory threadFactory,//线程工厂RejectedExecutionHandler handler//拒绝策略)
{...
}

4.线程池的执行顺序
线程池按以下行为执行任务

  • 当线程数小于核心线程数时,创建线程。
  • 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  • 当线程数大于等于核心线程数,且任务队列已满,若线程数小于最大线程数,创建线程。
  • 若线程数等于最大线程数,则执行拒绝策略

5.线程池的参数详解

  • corePoolSize
    核心线程数,默认为1。
    设置规则:
    CPU密集型(CPU密集型也叫计算密集型,指的是运算较多,cpu占用高,读/写I/O(硬盘/内存)较少):corePoolSize = CPU核数 + 1
    IO密集型(与cpu密集型相反,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。):corePoolSize = CPU核数 * 2
  • maximumPoolSize
    最大线程数,默认为Integer.MAX_VALUE
    一般设置为和核心线程数一样
  • keepAliveTime
    线程空闲时间,默认为60s,一般设置为默认60s
  • unit
    时间单位,默认为秒
  • workQueue
    队列,当线程数目超过核心线程数时用于保存任务的队列。(BlockingQueue workQueue)此队列仅保存实现Runnable接口的任务。(因为线程池的底层BlockingQueue的泛型为Runnable)
    无界队列
    队列大小无限制,常用的为无界的LinkedBlockingQueue,使用该队列作为阻塞队列时要尤其当心,当任务耗时较长时可能会导致大量新任务在队列中堆积最终导致OOM。阅读代码发现,Executors.newFixedThreadPool 采用就是 LinkedBlockingQueue,而博主踩到的就是这个坑,当QPS很高,发送数据很大,大量的任务被添加到这个无界LinkedBlockingQueue 中,导致cpu和内存飙升服务器挂掉。
    当然这种队列,maximumPoolSize 的值也就无效了。当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
    有界队列
    当使用有限的 maximumPoolSizes 时,有界队列有助于防止资源耗尽,但是可能较难调整和控制。常用的有两类,一类是遵循FIFO原则的队列如ArrayBlockingQueue,另一类是优先级队列如PriorityBlockingQueue。PriorityBlockingQueue中的优先级由任务的Comparator决定。
    使用有界队列时队列大小需和线程池大小互相配合,线程池较小有界队列较大时可减少内存消耗,降低cpu使用率和上下文切换,但是可能会限制系统吞吐量。
    同步移交队列
    如果不希望任务在队列中等待而是希望将任务直接移交给工作线程,可使用SynchronousQueue作为等待队列。SynchronousQueue不是一个真正的队列,而是一种线程之间移交的机制。要将一个元素放入SynchronousQueue中,必须有另一个线程正在等待接收这个元素。只有在使用无界线程池或者有饱和策略时才建议使用该队列。
    原文:https://blog.csdn.net/riemann_/article/details/104704197
  • threadFactory
    线程工厂,用来创建线程。
    为了统一在创建线程时设置一些参数,如是否守护线程,线程一些特性等,如优先级。通过这个TreadFactory创建出来的线程能保证有相同的特性。
    它是一个接口类,而且方法只有一个,就是创建一个线程。
    如果没有另外说明,则在同一个ThreadGroup 中一律使用Executors.defaultThreadFactory() 创建线程,并且这些线程具有相同的NORM_PRIORITY 优先级和非守护进程状态。
    通过提供不同的 ThreadFactory,可以改变线程的名称、线程组、优先级、守护进程状态,等等。
    如果从newThread 返回 null 时ThreadFactory 未能创建线程,则执行程序将继续运行,但不能执行任何任务。
  • handler
    拒绝策略,默认是AbortPolicy,会抛出异常。
    当线程数已经达到maxPoolSize,且队列已满,会拒绝新任务。
    当线程池被调用shutdown()后,会等待线程池里的任务执行完毕再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务。
    AbortPolicy 丢弃任务,抛运行时异常。
    CallerRunsPolicy 由当前调用的任务线程执行任务。
    DiscardPolicy 忽视,什么都不会发生。
    DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务。

6.ThreadPoolExecutor和spring封装的ThreadPoolTaskExecutor案例
ThreadPoolExecutor是Java的线程池
ThreadPoolTaskExecutor是spring封装的线程池

package com.thgy.bc.common.config;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.*;@Slf4j
@Configuration
public class ThreadPoolConfig {@Beanpublic ThreadPoolTaskExecutor threadPoolTaskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();int i = Runtime.getRuntime().availableProcessors();//核心线程数目executor.setCorePoolSize(i * 2);//指定最大线程数executor.setMaxPoolSize(i * 2);//队列中最大的数目executor.setQueueCapacity(i * 2 * 10);//线程名称前缀executor.setThreadNamePrefix("ThreadPoolTaskExecutor-");//rejection-policy:当pool已经达到max size的时候,如何处理新任务//CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行//对拒绝task的处理策略executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//当调度器shutdown被调用时等待当前被调度的任务完成executor.setWaitForTasksToCompleteOnShutdown(true);//线程空闲后的最大存活时间executor.setKeepAliveSeconds(60);//加载executor.initialize();log.info("初始化线程池成功");return executor;}@Beanpublic ThreadPoolExecutor threadPoolExecutor() {//获取cpu核心数int i = Runtime.getRuntime().availableProcessors();//核心线程数int corePoolSize = i * 2;//最大线程数int maximumPoolSize = i * 2;//线程无引用存活时间long keepAliveTime = 60;//时间单位TimeUnit unit = TimeUnit.SECONDS;//任务队列,接收一个整型的参数,这个整型参数指的是队列的长度,//ArrayBlockingQueue(int,boolean),boolean类型的参数是作为可重入锁的参数进行初始化,默认false,另外初始化了notEmpty、notFull两个信号量。BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue(i * 2 * 10);//1. 同步阻塞队列 (put,take),直接提交。直接提交策略表示线程池不对任务进行缓存。新进任务直接提交给线程池,当线程池中没有空闲线程时,创建一个新的线程处理此任务。// 这种策略需要线程池具有无限增长的可能性。实现为:SynchronousQueue//2. 有界队列。当线程池中线程达到corePoolSize时,新进任务被放在队列里排队等待处理。有界队列(如ArrayBlockingQueue)有助于防止资源耗尽,// 但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,// 但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,// CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。//3. 无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。// 这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,// 适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。//线程工厂//defaultThreadFactory()//返回用于创建新线程的默认线程工厂。//privilegedThreadFactory()//返回一个用于创建与当前线程具有相同权限的新线程的线程工厂。ThreadFactory threadFactory =Executors.defaultThreadFactory();//拒绝执行处理器RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();//创建线程池ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);return threadPoolExecutor;}
}

7.jdk自带的四种线程池创建方式

// 第一种线程池:固定个数的线程池,可以为每个CPU核绑定一定数量的线程数
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(processors * 2);
// 缓存线程池,无上限
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 单一线程池,永远会维护存在一条线程
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
// 固定个数的线程池,可以执行延时任务,也可以执行带有返回值的任务。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

8.队列的详解
参考:https://www.cnblogs.com/aspirant/p/8657801.html

9.调用线程池的线程案例

public List<AccountRecordVO> requestTest() throws ExecutionException, InterruptedException {List<String> ids = Lists.newArrayList();ids.add("1");ids.add("2");ids.add("3");ids.add("4");//有返回值的情况,定义接收返回值List<AccountRecordVO> futureList2 = Lists.newArrayList();//分布式计数器,若业务不需要则可以不定义CountDownLatch countDownLatch = new CountDownLatch(ids.size());for (String id : ids) {//调用线程池的线程执行任务threadPoolTaskExecutor.submit(new Runnable() {@Overridepublic void run() {test(Lists.newArrayList(id),futureList2);//计数器-1countDownLatch.countDown();}});}//await阻塞,直到计数器为0countDownLatch.await();System.out.println("主线程"+"====");return futureList2;}public List<AccountRecordVO> test(List<String> ids, List<AccountRecordVO> list2){//随便写的业务逻辑代码,无实际意义,仅作演示System.out.println("线程体" + "====");List<AccountRecordVO> accountRecordVOS = Lists.newArrayList();int i = 0;AccountRecordVO accountRecordVO = new AccountRecordVO();accountRecordVO.setUserId("123");accountRecordVO.setAmount(12333);for (String id : ids){accountRecordVOS.add(accountRecordVO);list2.add(accountRecordVO);}try{Thread.sleep(Long.valueOf("1000"));}catch (Exception e){log.error(e.getMessage());}System.out.println("线程体结束" + "====");return accountRecordVOS;}

线程池ThreadPoolExecutor详解(整理详细)相关推荐

  1. 线程池(ThreadPoolExecutor)详解

    线程池 线程池 线程池种类: ThreadPoolExecuter 类关系 结构 自定义线程池参数: 线程池的大小(maximumPoolSize): JDK提供的线程池 singleThreadPo ...

  2. async spring 默认线程池_Spring boot注解@Async线程池实例详解

    这篇文章主要介绍了Spring boot注解@Async线程池实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 从Spring3开始提供了@A ...

  3. python线程池原理_Python定时器线程池原理详解

    这篇文章主要介绍了Python定时器线程池原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 定时器执行循环任务: 知识储备 Timer(int ...

  4. 线程池源代码详解,参数详解

    线程池源代码详解,参数详解 ThreadPoolExecutor 构造函数源代码 public ThreadPoolExecutor(int corePoolSize, int maximumPool ...

  5. Java线程池ThreadPool详解

    Java线程池ThreadPool详解 1. 线程池概述 1.1 线程池简介 1.2 线程池特点 1.3 线程池解决问题 2. 线程池原理分析 2.1 线程池总体设计 2.6 线程池流转状态 2.2 ...

  6. java线程池使用详解ThreadPoolExecutor使用示例

    一 使用线程池的好处 二 Executor 框架 2.1 简介 2.2 Executor 框架结构(主要由三大部分组成) 1) 任务(Runnable /Callable) 2) 任务的执行(Exec ...

  7. python停止线程池_详解python中Threadpool线程池任务终止示例代码

    需求 加入我们需要处理一串个位数(0~9),奇数时需要循环打印它:偶数则等待对应时长并完成所有任务:0则是错误,但不需要终止任务,可以自定义一些处理. 关键点 定义func函数处理需求 callbac ...

  8. java线程池使用详解

    http://automaticthoughts.iteye.com/blog/1612388 一 简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使 ...

  9. java线程池详解及五种线程池方法详解

    基础知识 Executors创建线程池 Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可,比如Executors.newFixedThreadPool(int nThrea ...

最新文章

  1. 软件配置文件如何读写
  2. LIBRARY_PATH和LD_LIBRARY_PATH环境变量的区别
  3. Centos7+nginx1.12+mysql5.7+php7环境安装
  4. java uuid 效率_java uuid第一次性能
  5. [react-router] React-Router 4怎样在路由变化时重新渲染同一个组件?
  6. 知乎万赞:人并不是活一辈子,而是活几个瞬间
  7. 计算机xp用户丢失,WinXP电脑硬盘分区表丢失的解决方法
  8. Ubuntu14.04中安装ROS Indigo(亲测)
  9. 数据库备份的几种方法
  10. ubuntu16.04中将python3设置为默认
  11. docker的安装--基于docker1.6
  12. ImportError: _C.cpython-36m-x86_64-linux-gnu.so: undefined symbol: _ZN2at4_ops6narrow4callERKNS_6Ten
  13. 宝塔面板 安装与使用教程
  14. Python基础入门:(一)从变量到异常处理 --阿里云天池
  15. win10怎么将计算机放桌面壁纸,Win10专业版无法设置电脑桌面壁纸怎么办?
  16. 公式编译器AxMath安装包及在word中使用的教程
  17. 163邮箱接口post登录战网(一)
  18. pyecharts:日历图实战
  19. 科目一计算机答题错了能修改吗,科目一可要是错了可以修改吗
  20. mysql中数据发生变化时判断_MySql插入记录时判断

热门文章

  1. 组装一台计算机需要的配件,组装一台电脑需要哪些配件【详细列举】
  2. 计网笔记:奈氏准则 香农定理
  3. Android AudioTrack 播放封装及测试
  4. 阿里前员工撰文:马云的野心
  5. 旋转编码器的集电极开路输出、电压输出、互补输出和线性驱动输出之间的区别是什么
  6. python 读取mat文件,python读取并写入mat文件的方法
  7. 为什么 95% 自学成才的开发人员很快就转行了?
  8. MySQL总结二 宽字节注入
  9. 元朝书法家赵孟頫、鲜于枢
  10. 小白的数字电路逻辑设计笔记(一)----绪论