线程池总结(三大方法,七大参数,四中拒绝策略)
三大方法
- 使用Executors创建线程池的三大方法:
Executors.newSingleThreadExecutor()
创建只能容纳一个线程的线程池,这个线程池相当于只能容纳一个线程的容量。
ExecutorService threadPool = Executors.newSingleThreadExecutor();// 单个线程
Executors.newFixedThreadPool()
创建一个固定容纳最多指定线程池的线程容量
ExecutorService threadPool = Executors.newFixedThreadPool(5);
Executors.newCachedThreadPool()
创建一个可以伸缩的线程池,根据实际线程来伸缩
ExecutorService threadPool = Executors.newCachedThreadPool();//可伸缩的线程池
以上的三种创建线程池的方法,底层都是使用了ThreadPoolExecutor(6大参数)来创建的!
不信你往下看
以下是三种方法的底层,本质是:ThreadPoolExecutor()
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
七大参数
ThreadPoolExecutor()源码
public ThreadPoolExecutor(int corePoolSize, //核心线程池大小
int maximumPoolSize,//最大线程池大小
long keepAliveTime,//超时没有人调用就会释放
TimeUnit unit,//超时单位
BlockingQueue<Runnable> workQueue,//阻塞队列
ThreadFactory threadFactory,//线程工厂:创建线程,一般不用动
RejectedExecutionHandler handler) {//拒绝策略
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = (System.getSecurityManager() == null)
? null
: AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
以上是ThreadPoolExecutor的构造方法
七大参数就好笔比银行排队等待人数。
- 第一个参数corePoolSize就好比,银行今天只开放了两个窗口来处理事务
Core
部分,核心线程池数 - 第二个参数maximumPoolSize就好比,银行所拥有的最大客服窗口。到阻塞队列满的时候需要增加窗口来,让阻塞队列尽快减小。
- 第三个参数keepAliveTime就是设置超时的时间,没有人调用就会被释放
- 第四个参数unit就是超时时间的单位:TimeUnit.SECONDS 秒
- 第五个参数workQueue就是,阻塞队列,相当于候客厅等待的人数单位是BlockingQueue。
- 第六个参数threadFactory是一般不需要改变,直接使用Executors.defaultThreadFactory()默认值就好了。
- 第六个参数handler是拒绝策略,一般我们分为四种拒绝策略
handler= new ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常
handler= new ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常
handler= new ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列
handler= new ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务
手动创建线程池
package com.chen.pool;
import java.util.concurrent.*;
/**
* @Author 晨边#CB
* @Date:created in 2020/5/15 15:32
* @Version V1.0
**/
public class Demo02 {
public static void main(String[] args) {
//自定义线程。
/**
* 最大线程到底该如何定义
* 1.CPU: 密集型,几核,就是几。可以保持CPU的效率最高
* 2.IO 密集型->判断你的程序十分耗IO的线程
* 程序: 15个大型任务,io 十分占用资源!
*/
//获取CPU的核数
System.out.println(Runtime.getRuntime().availableProcessors());
ExecutorService threadPool = new ThreadPoolExecutor(2,5,3, TimeUnit.SECONDS,new LinkedBlockingDeque<>(3)
, Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());//可伸缩的线程池
//最后一个参数的策略是,银行满了,还有人进来,就不处理这个人的,抛出异常
//程序结束要关闭线程池
try{
for (int i = 1; i < 5; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}