对于线程池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使之执行.如果一个线程它大部分时间花费在等待某个事件响应的发生然后才予以响应:或者如果在一定期间内重 ...
随机推荐
- 开源 Open Source
FREE 开源不等于免费 代表自由 开源 Open Source软件和源代码提供给所有人,自由分发软件和源代码能够修改和创建衍生作品软件分类:商业 收费使用 代码不公开共享 免费用 代码不公开 ...
- linux 查看nginx的安装路径等信息
做个随笔,记录一下. 想查看nginx的配置文件,但不知道nginx是安装在哪个目录下? ps -ef | grep nginx Linux在启动一个进程时,系统会在/proc下创建一个以PID命名的 ...
- 设备屏幕与Size Class对应
- Linux常用命令合集(一)
1.处理目录的常用命令: ls(英文全拼:list files): 列出目录及文件名 cd(英文全拼:change directory):切换目录 pwd(英文全拼:print work direct ...
- ABAP CA CO CS CP 等操作符
DATA: L_STR1 TYPE STRING, L_STR2 TYPE STRING. L_STR1 = 'ca'. "匹配字符 L_STR2 = 'hubab'. "被匹配字 ...
- Java踩坑记系列之Arrays.AsList
java.util.Arrays的asList方法可以方便的将数组转化为集合,我们平时开发在初始化ArrayList时使用的比较多,可以简化代码,但这个静态方法asList()有几个坑需要注意: 一. ...
- centos6-增加阿里yum源
1.获取阿里的yum源覆盖本地官方yum源 wget -O /etc/yum.repos.d/CentOS-ali.repo http://mirrors.aliyun.com/repo/Centos ...
- Centos7安装Gitlab11
一.基础介绍 1.简介 一个基于GIT的源码托管解决方案 基于rubyonrails开发 集成了nginx postgreSQL redis sidekiq等组件 2.安装要求 2g内存以上,有点占内 ...
- day81:luffy:课程分类页面&课程信息页面&指定分类显示课程信息&分页显示课程信息
目录 1.构建课程前端初始页面 2.course后端的准备工作 3.后端实现课程分类列表接口 4.前端发送请求-获取课程分类信息 5.后端实现课程列表信息的接口 6.前端显示列表课程信息 7.按照指定 ...
- 【jmeter】实现接口关联的两种方式:正则表达式提取器和json提取器
关联通俗来讲就是把上一次请求的返回内容中的部分截取出来保存为参数,用来传递给下一个请求使用. 示例: 1.用户密码进行登录,登录后生成authentication 2.需要将登录接口响应结果中auth ...