为什么要用线程池
线程不是越多越好?
-
线程在Java中是一个对象,更是操作系统的资源,线程创建、销毁需要时间。如果创建时间+销毁时间> 执行任务时间就很不合算。
-
Java对象占有堆内存,操作系统线程占用系统内存,根据jvm规范,一个线程默认最大栈大小1M,这个栈空间是需要从系统内存中分配的。线程越多,会消耗很多的内存。
-
操作系统需要频繁切换线程上下文(大家都想被运行),影响性能。
线程池的推出,就是为了方便的控制线程数量。
从时间、空间、线程切换三方面去思考。
线程池原理 - 概念
-
线程池管理器:用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务。
-
工作线程:线程池中线程,在没有任务时处于等待状态,可以循环的执行任务。
-
任务接口:每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完成后的收尾工作,任务的执行状态等。
-
任务队列:用于存放没有处理的任务。提供一种缓冲机制。
线程池API - 接口定义和实现类
类型 | 名称 | 描述 |
---|---|---|
接口 | Executor | 最上层的接口,定义了执行任务的方法execute |
接口 | ExecutorService | 继承了Executor接口,扩展了Callable、Future、关闭方法 |
接口 | ScheduledExecutorService | 继承了ExecutorService,增加了定时任务相关的方法 |
实现类 | ThreadPoolExecutor | 基础、标准的线程池实现 |
实现类 | ScheduledThreadPoolExecutor | 继承了ThreadPoolExecutor,实现了ScheduledExecutorService中相关定时任务的方法 |
可以认为ScheduledThreadPoolExecutor是最丰富的实现类
线程池API - 方法定义
截屏2020-02-13上午10.22.29.png 截屏2020-02-13上午10.24.30.png线程池API - Executors工具类
截屏2020-02-13上午10.28.26.png线程池原理 - 任务executor过程
-
是否达到核心线程数量?没达到,创建一个工作线程来执行任务。
-
工作队列是否已满? 没满,则将新提交的任务存储在工作队列里。
-
是否达到线程池最大数量? 没达到,则创建一个新的工作线程来执行任务。
-
最后,执行拒绝策略来处理这个任务。
特殊的线程池信息
-
线程池信息: 核心线程数量5,最大数量5,无界队列,超出核心线程数量的线程存活时间:5秒
也就是核心线程数量等于最大数量,且无界队列时,固定线程数量,超过数量的任务进入队列中等待被执行。
-
核心线程数量0,最大数量Integer.MAX_VALUE,
SynchronousQueue
队列,超出核心线程数量的线程存活时间:60秒直接创建需要运行任务数量的线程数量,线程存活时间60s。
SynchronousQueue队列
SynchronousQueue
是一个内部只能包含一个元素的队列。插入元素到队列的线程被阻塞,直到另一个线程从队列中获取了队列中存储的元素。同样,如果线程尝试获取元素并且当前不存在任何元素,则该线程将被阻塞,直到线程将元素插入队列。将这个类称为队列有点夸大其词。这更像是一个点。
-
核心线程数量5,最大数量Integer.MAX_VALUE,DelayedWorkQueue延时队列,超出核心线程数量的线程存活时间:0秒
定时执行线程池信息:3秒后执行,一次性任务,到点就执行
和
Executors.newScheduledThreadPool()
一样的
-
调用shutdown后,不接收新的任务,会任务执行结束,追加的任务在线程池关闭后,无法再提交,会被拒绝执行。
threadPoolExecutor.shutdown();
-
调用shutdownnow后,队列中的线程不再执行,运行中的线程被终止,追加的任务在线程池关闭后,无法再提交,会被拒绝执行。
List<Runnable> shutdownNow = threadPoolExecutor.shutdownNow();
把终止的线程返回。
测试代码:
public class Demo7 {
//测试:提交15个执行时间需要3秒的任务,看超过大小的2个,对应的处理情况
public void testCommon(ThreadPoolExecutor threadPoolExecutor) throws InterruptedException {
for (int i = 0 ; i < 15 ; i++){
int finalI = I;
threadPoolExecutor.submit(()->{
System.out.println("开始执行,任务" + finalI);
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务" + finalI + "运行完毕");
});
System.out.println("任务提交成功");
}
// 查看线程数量,查看队列等待数量
Thread.sleep(5000L);
System.out.println("当前线程池线程数量为:" + threadPoolExecutor.getPoolSize());
System.out.println("当前线程池线程等待的数量为:" + threadPoolExecutor.getQueue().size());
// 等待15秒,查看线程数量和队列数量(理论上,会被超出核心线程数量的线程自动销毁)
Thread.sleep(15000L);
System.out.println("当前线程池线程数量为:" + threadPoolExecutor.getPoolSize());
System.out.println("当前线程池线程等待的数量为:" + threadPoolExecutor.getQueue().size());
}
/**
* 1、线程池信息: 核心线程数量5,最大数量10,无界队列,超出核心线程数量的线程存活时间:5秒, 指定拒绝策略的
*
* @throws Exception
*/
private void threadPoolExecutor1() throws Exception{
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,10,5,TimeUnit.SECONDS,
new LinkedBlockingQueue<>());
testCommon(threadPoolExecutor);
}
/**
* 2、 线程池信息: 核心线程数量5,最大数量10,队列大小3,超出核心线程数量的线程存活时间:5秒, 指定拒绝策略的
*
* @throws Exception
*/
private void theadPoolExecutor2() throws Exception{
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("有任务被拒绝了");
}
});
testCommon(threadPoolExecutor);
}
/**
* 3、 线程池信息: 核心线程数量5,最大数量5,无界队列,超出核心线程数量的线程存活时间:5秒
*
* @throws Exception
*/
private void threadPoolExecutor3() throws Exception{
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,5,5,TimeUnit.SECONDS,
new LinkedBlockingQueue<>());
testCommon(threadPoolExecutor);
}
/**
* 4、 线程池信息:
* 核心线程数量0,最大数量Integer.MAX_VALUE,SynchronousQueue队列,超出核心线程数量的线程存活时间:60秒
*
* @throws Exception
*/
private void threadPoolExecutor4() throws Exception{
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0,Integer.MAX_VALUE,60,TimeUnit.SECONDS,
new SynchronousQueue<>());
testCommon(threadPoolExecutor);
}
/**
* 5、 定时执行线程池信息:3秒后执行,一次性任务,到点就执行 <br/>
* 核心线程数量5,最大数量Integer.MAX_VALUE,DelayedWorkQueue延时队列,超出核心线程数量的线程存活时间:0秒
*
* @throws Exception
*/
private void threadPoolExecutor5() throws Exception{
//和Executors.newScheduledThreadPool()是一样的
ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
threadPoolExecutor.schedule(()->{
System.out.println("任务被执行,现在的时间为:" + System.currentTimeMillis());
},3000L,TimeUnit.MILLISECONDS);
System.out.println("任务提交成功,现在的时间为:" + System.currentTimeMillis() + "当前线程池中的线程数量" + threadPoolExecutor.getPoolSize());
}
/**
* 6、 定时执行线程池信息:线程固定数量5 ,<br/>
* 核心线程数量5,最大数量Integer.MAX_VALUE,DelayedWorkQueue延时队列,超出核心线程数量的线程存活时间:0秒
*
* @throws Exception
*/
private void threadPoolExecutor6(){
ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
threadPoolExecutor.scheduleWithFixedDelay(()->{
System.out.println("任务被执行,现在的时间为:" + System.currentTimeMillis());
},2000L,1000L,TimeUnit.MILLISECONDS);
threadPoolExecutor.scheduleAtFixedRate(()->{
System.out.println("任务被执行,现在的时间为:" + System.currentTimeMillis());
},2000L,1000L,TimeUnit.MILLISECONDS);
}
public static void main(String[] args) throws Exception {
Demo7 demo7 = new Demo7();
// demo7.threadPoolExecutor1();
// demo7.theadPoolExecutor2();
// demo7.threadPoolExecutor3();
// demo7.threadPoolExecutor4();
// demo7.threadPoolExecutor5();
// demo7.threadPoolExecutor6();
}
}
网友评论