对于线程池ThreadPool的学习总结
线程池:就是一个管理线程的池子。
优点:
- 它帮我们管理线程,避免增加创建线程和销毁线程的资源损耗。因为线程其实也是一个对象,创建一个对象,需要经过类加载过程,销毁一个对象,需要走GC垃圾回收流程,都是需要资源开销的。
- 提高响应速度。 如果任务到达了,相对于从线程池拿线程,重新去创建一条线程执行,速度肯定慢很多。
- 重复利用。 线程用完,再放回池子,可以达到重复利用的效果,节省资源。
一、线程池的创建
线程池可以通过ThreadPoolExecutor来创建
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long
keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
//corePoolSize: 线程池核心线程数最大值
//maximumPoolSize: 线程池最大线程数大小
//keepAliveTime: 线程池中非核心线程空闲的存活时间大小
//unit: 线程空闲存活时间单位
//workQueue: 存放任务的阻塞队列
//threadFactory: 用于设置创建线程的工厂,可以给创建的线程设置有意义的名字,可方便排查问题。
//handler: 线城池的饱和策略事件,主要有四种类型。
二、线程池处理流程

1,首先线程池判断基本线程池是否已满(< corePoolSize ?)?没满,创建一个工作线程来执行任务。满了,则进入下个流程。
2,其次线程池判断阻塞队列是否已满?没满,则将新提交的任务存储在阻塞队列里。满了,则进入下个流程。
3,最后线程池判断整个线程池是否已满(< maximumPoolSize ?)?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务。
三、线程池的阻塞队列
线程池阻塞队列:1、有界阻塞队列 2、无界阻塞队列 3、同步移交阻塞队列
public class QueueTest {
@Test
public void arrayBlockingQueue() throws InterruptedException {
/**
* 基于数组的有界阻塞队列,队列容量为10
*/
ArrayBlockingQueue queue =
new ArrayBlockingQueue<Integer>(10);
// 循环向队列添加元素
for (int i = 0; i < 20; i++) {
queue.put(i);
System.out.println("向队列中添加值:" + i);
}
}
@Test
public void linkedBlockingQueue() throws InterruptedException {
/**
* 基于链表的有界/无界阻塞队列,队列容量为10
*/
LinkedBlockingQueue queue =
new LinkedBlockingQueue<Integer>();
// 循环向队列添加元素
for (int i = 0; i < 20; i++) {
queue.put(i);
System.out.println("向队列中添加值:" + i);
}
}
@Test
public void test() throws InterruptedException {
/**
* 同步移交阻塞队列
*/
SynchronousQueue queue = new SynchronousQueue<Integer>();
// 插入值
new Thread(() -> {
try {
queue.put(1);
System.out.println("插入成功");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
// 删除值
new Thread(() -> {
try {
queue.take();
System.out.println("删除成功");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(1000L * 60);
}
}
四、线程池饱和策略
- Caller-runs调用者运行策略,即该线程的执行有调用的这个线程来执行,调用的线程会暂停原来的任务,转而去执行该任务,该任务执行完成后继续执行原来的任务
- AbortPolicy终止策略(系统默认), 该策略保证在线程池满的情况下任何试图提交任务到该线程池的线程的线程均会抛出,RejectedExecutionException,该异常导致调用线程的终止。但这种异常时可以捕获的(非检查型异常)。
- DiscardPolicy抛弃策略,该策略保证任何试图向满的线程池提交任务时,该任务的提交会立即返回,任务不会被提交,并且不会抛出任何形式的异常。
- DiscardOldestPolicy抛弃旧任务策略,这种模式下,将会抛弃下一个将要执行的任务,然后把刚提交的任务添加到任务队列,等待执行。
五、线程池的常用线程池
- newCachedThreadPool (创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。)
public static ExecutorService newCachedThreadPool(){
return new ThreadPoolExecutor(
0, // corePoolSoze == 0
Integer.MAX_VALUE, // maximumPoolSize 非常大
60L, // 空闲判定是60 秒
TimeUnit.SECONDS,
// 神奇的无存储空间阻塞队列,每个 put 必须要等待一个 take
new SynchronousQueue<Runnable>()
);
} newFixedThreadPool (创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。)
public static ExecutorService newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(
nThreads, // corePoolSize
nThreads, // maximumPoolSize == corePoolSize
0L, // 空闲时间限制是 0
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>() // 无界阻塞队列
);
}newSingleThreadPool (创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。)
public static ExecutorService newSingleThreadExecutor() {
return
new FinalizableDelegatedExecutorService
(
new ThreadPoolExecutor
(
1,
1,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory
)
);
}newScheduleThreadPool (创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。)
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
六、向线程池提交任务
提交任务有两种方式:1、有返回结果-sunmit 2、无返回结果-execute
public class RunTest {
@Test
public void submitTest()
throws ExecutionException, InterruptedException {
// 创建线程池
ExecutorService threadPool =
Executors.newCachedThreadPool();
/**
* 利用submit方法提交任务,接收任务的返回结果
*/
Future<Integer> future = threadPool.submit(() -> {
Thread.sleep(1000L * 10);
return 2 * 5;
});
/**
* 阻塞方法,直到任务有返回值后,才向下执行
*/
Integer num = future.get();
System.out.println("执行结果:" + num);
}
@Test
public void executeTest() throws InterruptedException {
// 创建线程池
ExecutorService threadPool =
Executors.newCachedThreadPool();
/**
* 利用execute方法提交任务,没有返回结果
*/
threadPool.execute(() -> {
try {
Thread.sleep(1000L * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
Integer num = 2 * 5;
System.out.println("执行结果:" + num);
});
Thread.sleep(1000L * 1000);
}
}
关于线程池五种状态:
线程池的5种状态:RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED.

1、RUNNING
(1). 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。
(2). 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
2、 SHUTDOWN
(1). 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。
(2). 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。
3、STOP
(1). 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。
(2). 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。
4、TIDYING
(1). 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。
当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;
可以通过重载terminated()函数来实现。
(2). 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。
当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。
5、 TERMINATED
(1). 状态说明:线程池彻底终止,就变成TERMINATED状态。
(2). 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。
最后实践Springboot中线程池的使用
@Configuration
@EnableAsync
public class ExecutorConfig { @Bean("exportServiceExecutor")
public Executor exportServiceExecutor(){
//创建线程池
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程数量:当前机器核心数
executor.setCorePoolSize (
Runtime.getRuntime().availableProcessors());
//最大线程数
executor.setMaxPoolSize(
Runtime.getRuntime().availableProcessors() * 2);
//队列大小
executor.setQueueCapacity(Integer.MAX_VALUE);
//线程池中线程名前缀
executor.setThreadNamePrefix("export-");
//线程池阻塞策略-拒绝策略:直接拒绝
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.AbortPolicy());
return executor;
}
}
@Async("exportServiceExecutor") //指定线程池
public void executorTest(){
System.out.println("测试线程");
}
对于线程池ThreadPool的学习总结的更多相关文章
- 关于线程池ThreadPool的学习
学习重点ThreadPool.SetMinThreads(out workerThreads, out completionPortThreads).这是整个线程池的关键. 而ThreadPool. ...
- java核心知识点学习----重点学习线程池ThreadPool
线程池是多线程学习中需要重点掌握的. 系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互.在这种情形下,使用线程池可以很好的提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考 ...
- C#多线程学习 之 线程池[ThreadPool](转)
在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPo ...
- C#多线程学习 之 线程池[ThreadPool]
在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPo ...
- [转]C#多线程学习 之 线程池[ThreadPool]
在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPo ...
- 多线程系列 线程池ThreadPool
上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...
- 多线程系列(2)线程池ThreadPool
上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...
- 线程池ThreadPool实战
线程池ThreadPool 线程池概念 常用线程池和方法 1.测试线程类 2.newFixedThreadPool固定线程池 3.newSingleThreadExecutor单线程池 4.newCa ...
- 线程池ThreadPool的初探
一.线程池的适用范围 在日常使用多线程开发的时候,一般都构造一个Thread示例,然后调用Start使之执行.如果一个线程它大部分时间花费在等待某个事件响应的发生然后才予以响应:或者如果在一定期间内重 ...
随机推荐
- RocketMQ扫盲篇
本篇博客主要参考: <浅入浅出>-RocketMQ 敖丙 APACHE-RocketMQ Gitee RocketMQ官方文档 RocketMQ 实战与进阶 GitChat 又是好久没有写 ...
- matlab cvx工具箱解决线性优化问题
题目来源:数学建模算法与应用第二版(司守奎)第一章习题1.4 题目说明 作者在答案中已经说明,求解上述线性规划模型时,尽量用Lingo软件,如果使用Matlab软件求解,需要做变量替换,把二维决策变量 ...
- 经典剪枝算法的例题——Sticks详细注释版
这题听说是道十分经典的剪枝算的题目,不要问我剪枝是什么,我也不知道,反正我只知道用到了深度搜索 我参考了好多资料才悟懂,然后我发现网上的那些大神原理讲的很明白,但代码没多少注释,看的很懵X,于是我抄起 ...
- 前端基础——HTML(一)
HTML html超文本标记语言 前端三层 HTML结构层 css样式层 JavaScript行为层 其他多媒体内容(图片,音频等等) 互联网运行过程 客 --http请求--> 服 户 htt ...
- Nginx的正向代理-反向代理-负载均衡
正向代理与反向代理[总结] 1.前言 最近工作中用到反向代理,发现网络代理的玩法还真不少,网络背后有很多需要去学习.而在此之前仅仅使用了过代理软件,曾经为了访问google,使用了代理软件,需 ...
- RAM ROM区别记忆
我老是忘这个 1.概念 RAM即随机存储内存,这种存储器在断电时将丢失其存储内容,故主要用于存储短时间使用的程序.ROM即只读内存,是一种只能读出事先所存数据的固态半导体存储器. 2.对比 手机中的R ...
- c#封装ActiveX接口实践分析
ActiveX接口 是一个开放的集成平台,为开发人员.用户和 Web生产商提供了一个快速而简便的在 Internet 和 Intranet 创建程序集成和内容的方法. 使用 ActiveX, 可轻松方 ...
- Python+Post请求中涉及到多个参数data方法的应用
进行post请求,Python提供了httplib.urllib2,同时也可以引用requests模块的一些方法.前几天做持续集成,运用requests写了一个post请求.代码如下: import ...
- 跟我一起学Redis之Redis配置文件啃了一遍之后,从尴尬变得有底气了
前言 秋高气爽的一天,那时候年轻帅气的我正在参照着搜索引擎写代码,迷之微笑般的敲着键盘(又从搜索引擎上找到代码案例啦),突然领导在小隔间里传来了呼唤声,然后有了以下场景: 领导:小Z,你过来一下: 当 ...
- AC 自动机刷题记录
目录 简介 第一题 第二题 第三题 第四题 第五题 第六题 简介 这就是用来记录我对于<信息学奥赛一本通 · 提高篇>一书中的习题的刷题记录以及学习笔记. 一般分专题来写(全部写一起可能要 ...