什么是Executor框架?
首先要了解什么是线程池?线程池是集中管理线程的,以实现线程的重用,降低资源消耗,提高响应速度,提高线程的可管理性等。线程用于执行异步任务,单个的线程既是工作单元也是执行机制,从JDK1.5开始,为了把工作单元与执行机制分离开,Executor框架诞生了,他是一个用于统一创建与运行的接口。Executor框架实现的就是线程池的功能。
ThreadPoolExecutor
线程池的真正实现类是 ThreadPoolExecutor,我们可以实现ThreadPoolExecutor 自定义线程池的方式,其次我们也可以使用Executor框架的 Executors类(java.util.concurrent包)创建封装好的线程。
而ThreadPoolExecutor 类参数最多,并且 Executors 封装的线程池底层都是基于ThreadPoolExecutor实现的。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
构造参数解释:
corePoolSize:核心线程数
maximumPoolSize:最大线程数
keepAliveTime:救急线程空闲时的最大生存时间
unit:时间单位
workQueue:阻塞队列(存放任务)
PriorityBlockingQueue:优先队列
threadFactory:线程工厂(给线程取名字)
handler:拒绝策略
了解了底层的ThreadPoolExecutor后,以 Executors 封装线程池使用为例:
package com.example.redislock.threadpools;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
/**
* 可重用固定线程数的线程池
* 核心线程数=最大线程数
* 无需超时时间,只需要设置核心线程数与threadFactory重命名线程即可
* 使用 LinkedBlockingQueue 阻塞队列
* 适用于任务量已知,相对耗时的任务
*/
ExecutorService executorService = Executors.newFixedThreadPool(100, new ThreadFactory(){
private AtomicInteger atomicInteger = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r,"myThread="+atomicInteger.getAndIncrement());
}
});
/**
* 根据需要创建新线程的线程池
* 核心线程数为0,最大线程数为Integer.MAX_VALUE,所以全是救急线程
* 生存时间为60秒,执行完毕自动释放
* 队列使用 SynchronOusQueue,没有容量,相当于一手交钱一手交货.
* 适合任务数比较密集,执行时间短的场景
*/
ExecutorService executorService1 = Executors.newCachedThreadPool(new ThreadFactory() {
private AtomicInteger atomicInteger = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "myThread=" + atomicInteger.getAndIncrement());
}
});
/**
* 使用单个worker线程的线程池
* 多个任务排队进行,线程数为 1 ,任务超过 1 时,放入无界队列中
* 队列使用 LinkedBlockingQueue
* 任务执行完也不会释放,需要手动释放.
* 任务执行失败没有补救措施,不可再用
*/
ExecutorService executorService2 = Executors.newSingleThreadExecutor(new ThreadFactory() {
private AtomicInteger atomicInteger = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "myThread=" + atomicInteger.getAndIncrement());
}
});
for (int i=0;i<21;i++){
executorService.execute(() -> {
System.out.println("ThreadName = "+Thread.currentThread().getName());
});
}
//线程状态变为 stop,不会再接收新任务,将队列中的任务返回,
// 并使用interrupt方法中断正在执行的任务,相当于全部任务中断.
executorService.shutdownNow();
//线程状态变为 shutdown,不会再接收新任务,但等待队列和已提交的任务会执行完.
executorService2.shutdown();
}
}
根据对应输出结果理解线程池:
newFixedThreadPool:固定100个线程数量,20个线程并发执行:
ThreadName = myThread=1
ThreadName = myThread=3
ThreadName = myThread=2
ThreadName = myThread=4
ThreadName = myThread=5
ThreadName = myThread=11
ThreadName = myThread=6
ThreadName = myThread=12
ThreadName = myThread=9
ThreadName = myThread=10
ThreadName = myThread=7
ThreadName = myThread=8
ThreadName = myThread=13
ThreadName = myThread=14
ThreadName = myThread=15
ThreadName = myThread=16
ThreadName = myThread=17
ThreadName = myThread=18
ThreadName = myThread=19
ThreadName = myThread=20
ThreadName = myThread=21
newCachedThreadPool:20个任务量,但是只有12个线程执行了,因为执行完的线程复用,继续执行其他任务。
ThreadName = myThread=1
ThreadName = myThread=3
ThreadName = myThread=4
ThreadName = myThread=5
ThreadName = myThread=2
ThreadName = myThread=6
ThreadName = myThread=3
ThreadName = myThread=8
ThreadName = myThread=1
ThreadName = myThread=2
ThreadName = myThread=10
ThreadName = myThread=7
ThreadName = myThread=2
ThreadName = myThread=11
ThreadName = myThread=4
ThreadName = myThread=5
ThreadName = myThread=8
ThreadName = myThread=6
ThreadName = myThread=3
ThreadName = myThread=9
ThreadName = myThread=12
newSingleThreadExecutor:多个任务排队进行,线程数为 1,依次执行。
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1
ThreadName = myThread=1