java多线程系列(六)---线程池原理及其使用
线程池
前言:如有不正确的地方,还望指正。
目录
- 认识cpu、核心与线程
- java多线程系列(一)之java多线程技能
- java多线程系列(二)之对象变量的并发访问
- java多线程系列(三)之等待通知机制
- java多线程系列(四)之ReentrantLock的使用
- java多线程系列(五)之synchronized ReentrantLock volatile Atomic 原理分析
- java多线程系列(六)之线程池原理及其使用
线程池的优点
- 重复利用已经创建的线程,减少创建线程和销毁线程的开销
- 提高响应速度,不需要等到线程创建就能立即执行
- 使用线程池可以进行统一分配,调优和监控
- 总的来说:降低资源消耗,提高响应速度,提高线程可管理性
线程池原理

- 提交任务
- 核心线程池(corePoolSize)是否已经满,如果未满的话就创建线程执行任务
- 否则查看队列(BlockingQueue)是否已满,未满的话,将任务存储在队列里
- 如果已经满了,看线程池(maximumPoolSize)是否已满,如果满的话按照拒绝处理任务策略(handler)处理无法执行的任务
- 如果未满,创建线程执行任务
ThreadPoolExecutor构造参数
- corePoolSize:核心池的大小,构建线程池后,并不会创建线程,当前线程数如果小于corePoolSize时,当要执行任务时,创建一个线程。当当前线程数等于corePoolSize,会将任务放入队列中
- maximumPoolSize:线程池最大数,也就是线程最多能创建的线程
- keepAliveTime:工作线程空闲后,保持存活的时间。默认情况下,如果当前线程数大于corePoolSize,那么一个线程如果没有任务,当空闲的时间大于keepAliveTime时,会终止该线程,直到线程数不超过corePoolSize
- workQueue:存储任务的队列,有几种种类型队列ArrayBlockingQueue(有界缓冲区,基于数组的队列,先进先出,必须指定大小,可以设置是否保持公平,以FIFO顺序访问),LinkedBlockingQueue(基于链表的队列,如果没有指定大小,默认为Integer.MAX_VALUE),SynchronousQueue(无界线程池,不管多少任务提交进来,直接运行)
- ThreadFactory:线程工厂,用来创建线程,通过线程工厂可以给创建的线程设置名字
- rejectedExecutionHandler:拒绝处理任务的策略AbortPolicy(直接放弃任务,抛出RejectedExecutionException异常),DiscardPolicy(放弃任务,不抛出异常),DiscardOldestPolicy(放弃最旧的未处理请求,然后重试 execute;如果执行程序已关闭,则会丢弃该任务),CallerRunsPolicy(它直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务)
ThreadPoolExecutor重要方法
- execute:在将来某个时间执行给定任务
- submit:提交一个任务用于执行,并返回一个表示该任务的 Future,和execute不同的是返回的是一个Future,可以在任务执行完毕之后得到任务执行结果
- shutdown:按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务。也就是说,中断没有正在执行任务的线程,等待任务执行完毕。
- shutdownnow: 尝试停止所有的活动执行任务、暂停等待任务的处理,并返回等待执行的任务列表。
线程池状态
volatile int runState;
static final int RUNNING = 0;
static final int SHUTDOWN = 1;
static final int STOP = 2;
static final int TERMINATED = 3;
- RUNNING:创建线程池后,初始状态为RUNNING
- SHUTDOWN:执行shutdown方法后,线程池处于SHUTDOWN状态
- STOP:执行shutdownNow方法后,线程池处于STOP状态
- TERMINATED:当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。
源码分析
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
}
- command是否为空,是的话抛出异常
- 如果当前线程是否小于corePoolSize,执行addIfUnderCorePoolSize方法,创建线程并执行任务
- 如果当前线程线程数大于等于corePoolSize或者执行addIfUnderCorePoolSize返回false,将当前任务放到队列中
- 如果线程池状态不是RUNNING状态或者任务无法加入到队列,并且线程数大于最大线程数,执行reject方法
- 流程跟上面的线程池原理相同
配置线程池
- cpu密集型和io密集型线程数的选择,cpu密集型不需要太多的线程,可以充分利用cpu资源,io密集型适当多线程,io阻塞时可以切换至另一线程。
- 优先级不同的的任务可以使用PriorityBlockingQueue来处理
- 建议使用有界队列,能够增加系统的稳定性(如果使用无界队列,当出现问题时候,队列无限增长,此时可能会占用大量内存,导致系统出现问题)和预警能力(当出现队列占满的时候,抛出异常,可以让开发人员及时发现)
线程池使用
public static void main(String[] args)
{
final Vector<Integer> vector = new Vector<Integer>();
//corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit,BlockingQueue
ThreadPoolExecutor tp = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
final Random random = new Random();
System.out.println(tp.getPoolSize());
for (int i = 0; i < 20; i++)
{
tp.execute(new Runnable()
{
public void run()
{
vector.add(random.nextInt());
}
});
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
tp.shutdown();
System.out.println("已完成的任务:"+tp.getCompletedTaskCount());
System.out.println("活动的线程数:"+tp.getActiveCount());
System.out.println("list大小:"+vector.size());
}
- 上面的代码我们自己构建了一个ThreadPoolExecutor,而Executor给我们提供了几个静态方法用于创建线程池,本质上只是设置了给定的参数而已
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- FixedThreadPool,顾名思义,一个固定大小的线程池,队列使用的无限制大小的链表阻塞队列
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
- 单线程线程池,同样队列使用的无限制大小的链表阻塞队列
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- 无界线程池,无论多少任务,直接运行,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
我觉得分享是一种精神,分享是我的乐趣所在,不是说我觉得我讲得一定是对的,我讲得可能很多是不对的,但是我希望我讲的东西是我人生的体验和思考,是给很多人反思,也许给你一秒钟、半秒钟,哪怕说一句话有点道理,引发自己内心的感触,这就是我最大的价值。(这是我喜欢的一句话,也是我写博客的初衷)
作者:jiajun 出处: http://www.cnblogs.com/-new/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如果觉得还有帮助的话,可以点一下右下角的【推荐】,希望能够持续的为大家带来好的技术文章!想跟我一起进步么?那就【关注】我吧。
java多线程系列(六)---线程池原理及其使用的更多相关文章
- Java多线程系列--“JUC线程池”02之 线程池原理(一)
概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...
- Java多线程系列--“JUC线程池”03之 线程池原理(二)
概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...
- Java多线程系列--“JUC线程池”04之 线程池原理(三)
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基 ...
- Java多线程系列--“JUC线程池”05之 线程池原理(四)
概要 本章介绍线程池的拒绝策略.内容包括:拒绝策略介绍拒绝策略对比和示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3512947.html 拒绝策略 ...
- Java多线程系列--“JUC线程池”06之 Callable和Future
概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...
- Java多线程系列--“JUC线程池”01之 线程池架构
概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容——线程池.内容包括:线程池架构 ...
- Java多线程系列 JUC线程池07 线程池原理解析(六)
关闭“线程池” shutdown()的源码如下: public void shutdown() { final ReentrantLock mainLock = this.mainLock; // ...
- Java多线程系列 JUC线程池05 线程池原理解析(四)
转载 http://www.cnblogs.com/skywang12345/p/3544116.html https://blog.csdn.net/programmer_at/article/d ...
- Java多线程系列 JUC线程池04 线程池原理解析(三)
转载 http://www.cnblogs.com/skywang12345/p/3509954.html https://blog.csdn.net/qq_22929803/article/det ...
随机推荐
- Latex加速: TexStudio的安装和使用
TexStudio可以加速Latex的编辑和写作,这里简单介绍一下TexStudio的安装,配置和使用.但是有一个重要的前提,TexStudio会使Latex源代码和pdf文件并排显示,比较占用桌面的 ...
- solr的基本概念
一.solr的基本概念 大家可以把solr搜索引擎看成一个数据库,不过是基于内存的.它可以存储信息,并且根据你的查询条件返回你想要的信息. 1.collection和core的概念 collectio ...
- Python爬虫小白---(二)爬虫基础--Selenium PhantomJS
一.前言 前段时间尝试爬取了网易云音乐的歌曲,这次打算爬取QQ音乐的歌曲信息.网易云音乐歌曲列表是通过iframe展示的,可以借助Selenium获取到iframe的页面元素, 而QQ音乐采用的是 ...
- 利用VNC远程登录Linux服务器简易版
我负责管理实验室的一台服务器,安装的系统是CentOS 6.7.使用pietty远程登录服务器(命令行) 需求:使实验室的同学和老师使用RealVNC远程登录服务器. 一,首先检查一下服务器是否安装V ...
- 数控G代码编程详解大全
一.G代码功能简述 G00------快速定位 G01------直线插补 G02------顺时针方向圆弧插补 G03------逆时针方向圆弧插补 G04------定时暂停 G05------通 ...
- Linux下搭建FTP服务器(Ubuntu16.04)
搞了下FTP服务器,基本上能遇到的问题都遇到了-.-! 先说步骤: 1.安装vsftpd软件包 sudo apt-get install vsftpd 2.打开配置文件 vim /etc/vsftpd ...
- 中国剩余定理(CRT)与欧拉函数[数论]
中国剩余定理 ——!x^n+y^n=z^n 想必大家都听过同余方程这种玩意,但是可能对于中国剩余定理有诸多不解,作为一个MOer&OIer,在此具体说明. 对于同余方程: x≡c1(mod m ...
- SSH三大框架的各自工作流程
一.Struts2的工作流程:1.用户在客户端发起请求,客户端会初始化一个servlet容器请求:2.servlet容器把请求会传递给context容器,context容器找到目标web工程.3.进行 ...
- Spring boot——logback 基础使用篇(一)
1 简单日志配置 spring boot内部使用Commons Logging来记录日志,但也保留外部接口可以让一些日志框架来进行实现,例如Java Util Logging,Log4J2还有Logb ...
- 【HTML】dl dt dd
摘要 看到没怎么使用过的html 标签,记录下 定义 dl 类似于 ul ,无任何样式,自定义列表容器, ul 为无序列表容器,ol 为有序列表容器 dt dd 类似于 li ,无任何样式,为帮助实现 ...