多线程学习笔记-深入理解ThreadPoolExecutor
java多线程中,线程池的最上层接口是Executor,ExecutorService实现了Executor,是真正的管理线程池的接口,ThreadPoolExecutor间接继承了ExecutorService,提供了多种具体的线程池实现,在日常开发中一般直接使用Executors工具类提供的几种常用ThreadPoolExecutor,下面详细介绍下ThreadPoolExecutor.
ThreadPoolExecutor基本参数
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1000L,
TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(20),
new ThreadPoolExecutor.CallerRunsPolicy());
corePoolSize:核心线程数的大小,也有说线程池最小线程数
maximumPoolSize:线程池最大线程数
keepAliveTime:当没有任务执行时,线程能存活的最大时间,这里说的线程是指大于corePoolSize,小于maximumPoolSize的线程
timeunit:keepAliveTime的时间单位
workQueue:用来存放task的堵塞队列,队列的选择和size的大小对线程池的运行有直接影响,默认有几种实现,后面详说.
rejectHandler:拒绝策略,当队列已满并且线程数达到maximumPoolSize时,再有新任务进来时会执行拒绝策略,默认集中实现,后面详说.
ThreadPool模型初始化
ThreadPool线程池初始化时,不会创建corePoolSIze的线程,也就是说在没有task进来的时候,线程池是空的,当有task进来的时候,开始创建线程,并且线程执行完task后不会销毁,而是驻留内存,直至达到corePoolSize,那什么时候线程数会再度增加达到maxPoolSize呢,这就取决于存放task的queue的size了,如果task的数量一直不超过指定的size那么就不会创建新的线程出来,反之,则会创建新的线程去执行task,那么新建出来的线程执行完task也会一直驻留内存吗?答案是不会,这时候就要看设置的keepAliveTime,如果在超过了这个时间后还是没有task去使用这个线程,则线程销毁,直至线程数等于corePoolSize.那么如果queue也满了,线程数也达到maxPoolsize,这时候怎么办呢,这时rejectHandler就会发挥作用,会根据我们指定的拒绝策略去处理这种场景.
Executors的几个默认实现
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}
1.newSingleThreadExecutor:创建一个单线程的线程池.如果这个线程在执行霍城中因为异常结束,则会创建一个新的线程来代替它,这个线程池保证所有任务的执行顺序是按照任务提交顺序进行.
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
2.newFixedThreadPool:创建一个固定大小的线程池.看源码可知,该实现创建了一个corePoolSize等于maximumPoolSize的线程池.
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}
3.newCachedThreadPool:创建一个可缓存的线程池.看源码可知corePoolSize=0,即当线程空闲时会被回收,当线程忙碌时又可以"源源不断"的创建新线程来执行task.
默认线程池实现中还有ScheduledThreadPoolExecutor,可以实现定时的一些功能,可用来代替Timer或者TimeTask.这里不再展开说.
线程池的堵塞队列
如何选择线程池的堵塞队列,取决我们的业务场景,即我们希望以一种什么样的排队策略来处理任务.排队通常有3种策略,对应下面几种queue.
直接提交(SynchronousQueue):不排队,这个队列不会存储task,会将调用方的task直接提交给线程,指定了SynchronousQueue的线程池通常会把maximumPoolSize配置的比较大,否则可能会导致没有足够的线程来执行task,而导致task无法放入queue而被丢弃或拒绝.
有界队列(ArrayBlockingQueue):通过指定ArrayBlockingQueue的size可以设置队列的最大存储个数,当超出这个个数时就会新建线程去执行task直至线程数达到maximumPoolSize,有界队列size的设置和maximumPoolSize的设置息息相关.会影响CPU的使用率以及系统吞吐量.
无界队列(不设定size的LinkedBlockingQueue):当线程数达到corePoolSize的仍有task进来时,会源源不断进队列,由于无解,maximumPoolSize参数会失效,线程数最大只能达到corPoolSize.
线程池拒绝策略
CallerRunsPolicy:使用调用方的线程来执行task,通常情况下调用方线程就是指我们所说的主线程,这样的好处是不会丢弃task,但是缺点也很明显,使用这种策略会堵塞主线程,进而拖慢主线程的整个调用时长.而基于此,该策略同时也减缓了新的task提交进来的速度(因为主线程本来只需要用来提交task就好了,现在直接去执行task,后面的task进来的速度就慢了).
AbortPolicy:这个策略简单粗暴,直接抛出异常,不跟你多BB,需要注意的是,这个是jdk的默认策略.
DiscardPolicy:这个和AbortPolicy差不多,区别是不会抛出异常,直接丢弃.
DiscardOldestPolicy:这也是一种丢弃策略,不过和上面的DiscardPolicy刚好相反,她丢弃的不是新进来的task而是在堵塞队列中存在时间最久的那个task,即丢弃最早进入队列并且还没有被执行的task.
多线程学习笔记-深入理解ThreadPoolExecutor的更多相关文章
- java多线程学习笔记——详细
一.线程类 1.新建状态(New):新创建了一个线程对象. 2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...
- 多线程学习笔记九之ThreadLocal
目录 多线程学习笔记九之ThreadLocal 简介 类结构 源码分析 ThreadLocalMap set(T value) get() remove() 为什么ThreadLocalMap的键是W ...
- JAVA多线程学习笔记(1)
JAVA多线程学习笔记(1) 由于笔者使用markdown格式书写,后续copy到blog可能存在格式不美观的问题,本文的.mk文件已经上传到个人的github,会进行同步更新.github传送门 一 ...
- java进阶-多线程学习笔记
多线程学习笔记 1.什么是线程 操作系统中 打开一个程序就是一个进程 一个进程可以创建多个线程 现在系统中 系统调度的最小单元是线程 2.多线程有什么用? 发挥多核CPU的优势 如果使用多线程 将计算 ...
- 微信小程序开发:学习笔记[7]——理解小程序的宿主环境
微信小程序开发:学习笔记[7]——理解小程序的宿主环境 渲染层与逻辑层 小程序的运行环境分成渲染层和逻辑层. 程序构造器
- Java多线程学习笔记(一)——多线程实现和安全问题
1. 线程.进程.多线程: 进程是正在执行的程序,线程是进程中的代码执行,多线程就是在一个进程中有多个线程同时执行不同的任务,就像QQ,既可以开视频,又可以同时打字聊天. 2.线程的特点: 1.运行任 ...
- java 多线程学习笔记
这篇文章主要是个人的学习笔记,是以例子来驱动的,加深自己对多线程的理解. 一:实现多线程的两种方法 1.继承Thread class MyThread1 extends Thread{ public ...
- Java多线程学习笔记--生产消费者模式
实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前 ...
- Java多线程学习笔记
进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...
随机推荐
- SQLServer安装和JDBC连接SQLServer
SQLServer 安装 参考链接: http://blog.csdn.net/sangjinchao/article/details/62044021?locationNum=6&fps=1 ...
- 图数据库项目DGraph的前世今生
本文由云+社区发表 作者:ManishRai Jain 作者:ManishRai Jain Dgraph Labs创始人 版权声明:本文由腾讯云数据库产品团队整理,页面原始内容来自于db weekly ...
- vue实用组件——圆环百分比进度条
因为所在公司临近年底突然宣布Game Over,导致我等小码农又要踏上一个艰辛的求职道路了.才眨眼功夫,年就过完了,快乐的时光总是很匆忙呀. 开年的第一个面试,面试官问我会不会自己写一个圆环进图圈,这 ...
- SpringBoot系列——MyBatis整合
前言 MyBatis官网:http://www.mybatis.org/mybatis-3/zh/index.html 本文记录springboot与mybatis的整合实例:1.以注解方式:2.手写 ...
- WPF 中图片的加载 ,使用统一资源标识符 (URI)
在wpf中,设置图片路径有2种方法: 1.xaml文件中,指定路径 <Button Name=" HorizontalAlignment="Right" Verti ...
- C#杂记-简化的初始化
对象说明 public class Person { public int Age{get; set;} public string Name{get; set;} List<Person> ...
- C# ListBox实现显示插入最新的数据的方法
在我们使用ListBox控件时,如果我们在里面不断的添加一条条数据,但是在我们添加的数据过多超过了ListBox显示的窗口时(此时会产生滑动条), 发现我们无法看到最新添加的数据.实现倒序显示此处有两 ...
- 让Mongo在Spring中跑起来
本文标题为<让Mongo在Spring中跑起来>,旨在Spring中如何成功连接MongoDB并对其进行增删改查等操作,由于笔者也是刚接触,对其中的一些原由也不甚了解,若有错误之处,敬请指 ...
- Xaramin IOS 开发常见问题
调试时提示找不到obj某某文件,勾选后编译,再取消勾选后再次调试 APP不能上网(而且无法通过配置允许上网的APP,因为根本 找不到需要的APP),不要使用IOS11测试版本,自动禁网 截图路径 %U ...
- 用webpack打包加密静态配置文件
webpack处理静态文件,如json.xml等配置文件,可以采用 copy-webpack-plugin 插件直接复制到打包后的文件夹下,但如果想采用一些手段隐藏一下这些配置文件的内容怎么办呢? 虽 ...