对于线程池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使之执行.如果一个线程它大部分时间花费在等待某个事件响应的发生然后才予以响应:或者如果在一定期间内重 ...
随机推荐
- 判断是否是胖子的shell脚本
read -p "请输入身高(m为单位): " HIGH if [[ ! "$HIGH" =~ [1].?[0-9]{,2}$ ]];then echo &qu ...
- C++学习---队列的构建及操作
一.循环队列 #include <iostream> using namespace std; #define MAXQSIZE 100 typedef struct { int* bas ...
- git学习(八) git stash操作
git stash命令的作用就是将目前还不想提交的但是已经修改的内容进行保存至堆栈中,后续可以在某个分支上恢复出堆栈中的内容.git stash作用的范围包括工作区和暂存区中的内容,没有提交的内容都会 ...
- Sword Art Online 刀剑神域
date: 2014-10-06 15:30:11 updated: 2014-10-06 15:30:11 [一] 他和她,第一次相见是在游戏里,两个角色的对话.现在说来都不算是正式见面呢. &qu ...
- Spring Shiro配置第三方SSO客户端登录
经过实践的Shiro配置,利用 sSOInterceptor 进行sso登录拦截 配置 @Configuration public class ShiroConfiguration extends B ...
- (CS229)监督学习应用和梯度下降
监督学习:基于标记数据的学习 监督学习又举了两个例子:回归问题regression在连续数据上的模型构建问题 和 分类问题 classification 在离散数据上的问题 无监督学习:未标记的学习 ...
- 常用物联网应用层协议(1)——先说HTTP协议
概念 简介 HTTP是一个属于应用层的面向对象的协议,目前使用最为广泛的是HTTP1.1协议.当然,许多网站已经开始支持HTTP2.0,HTTP2复杂度高于HTTP1.1,我们先从HTTP1.1说起. ...
- jdk1.8特性2
public class User { private Long id; private String userName; private String roleName; private Strin ...
- 关于nodejs中的增删改查
1.增加 router.post('/insert',function(req,res){ var name = req.body.name; var num = req.body.num; v ...
- DTU有哪些功能特点?
DTU指的是一种数据终端设备(Data Terminal unit),可以把它简单理解为下位GPRS发射终端,在进行通信的时候,传输数据的链路两端肯定是存在DTU,所传信息进行格式转换和数据整理效验都 ...