【JUC】线程池
【JUC】线程池
文章目录
- 【JUC】线程池
- 1. 创建线程池
- 2. 关闭线程池
- 3. 拒绝策略
- 4. 线程创建工厂
- 5. Executors工具类
- 5.1 创建单个线程的线程池
- 5.2 创建多个线程的线程池
1. 创建线程池
线程池的构造方法:
public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
int maximumPoolSize,//最大线程池大小
long keepAliveTime,//线程最大空闲时间
TimeUnit unit,//线程最大空闲时间的单位
BlockingQueue<Runnable> workQueue,//线程等待队列
ThreadFactory threadFactory,//线程创建工厂
RejectedExecutionHandler handler//拒绝策略
) {}
- corePoolSize:核心线程池大小,我们每向线程池提交一个多线程任务时,无论是否存在其他空闲线程,都会创建一个新的
核心线程
,直到到达核心线程池大小为止,之后会尝试复用线程资源。当然也可以在一开始就全部初始化好,调用prestartAllCoreThreads()
即可。 - maximumPoolSize:最大线程池大小,当线程池中所有的线程都处于运行状态并且对待队列也满了,那么就会直接尝试创建新的
非核心线程
运行,但是总线程数不能超过最大线程池大小。 - keepAliveTime:线程最大空闲时间,当
非核心线程
空闲超过一定时间,会自动销毁。 - unit:线程最大空闲时间的时间单位
- workQueue:线程等待队列,当线程池中
核心线程
已满时,就会将任务暂时存到等待队列中,直到有线程资源可用为止(核心线程和队列都满了,就会去尝试创建非核心线程)。 - threadFactory:线程创建工厂,我们可以干涉线程池中线程的创建过程,进行自定义。
- handler:拒绝策略,当等待队列和线程池都没有空间了,也不能再创建非核心线程了。此时来了一个新的多线程任务,那么只能拒绝了,这时就会根据当前设定的拒绝策略进行处理。
2. 关闭线程池
线程池.shutdownNow();//立马关闭线程池,取消所有等待中的任务以及试图中断正在执行的任务,关闭后无法再提交任务,一律拒绝。
线程池.shutdown();//执行完等待队列中的任务再关闭。
3. 拒绝策略
线程池的拒绝策略主要有以下四种:
- AbortPolicy(默认):直接抛异常。
- CallerRunsPolicy:直接让提交人物的线程执行这个任务,如主线程向线程池提交这个任务,那么就由主线程执行。
- DiscardOldestPolicy:丢弃队列中最近的一个任务,替换为当前任务。
- DiscardPolicy:什么也不做。
除了这四种策略外,我们也可以使用自定义的策略:
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4,3, TimeUnit.SECONDS,new SynchronousQueue<>(),
//自定义拒绝策略
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("自定义拒绝策略");
r.run();
}
}
);
4. 线程创建工厂
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS, new SynchronousQueue<>(),
//自定义线程工厂
new ThreadFactory() {
int count = 0;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "线程" + (++count));
}
},
//自定义拒绝策略
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("自定义拒绝策略");
r.run();
}
}
);
线程池在执行任务的过程中如果抛出了异常,那么线程池就会销毁这个线程。
5. Executors工具类
5.1 创建单个线程的线程池
除了自己创建线程池这一方法,我们也可以使用 Executors
工具类来快速创建线程池:
//创建一个只有一个线程的线程池
private static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();
它的内部实现如下所示:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
5.2 创建多个线程的线程池
private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);
它的内部实现如下:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
我们最终发现,该方法也是通过调用7个参数的线程池构造方法来创建的线程池。
它将核心线程数和最大线程数设置值相同,并且非核心线程的空闲时间设置为0,因为根本就没有非核心线程,全是核心线程,并且采用的是一个无界的LinkedBlockingQueue作为等待队列。