谈到线程池,只需要记住这三个词:三大方法,七大参数,四种拒绝策略轻松搞定!
1、线程池
在Java中,创建和销毁线程是非常费时的,可能加起来的运行时间可能远大于方法实行的时间,为了提高程序效率,我们需要尽可能的降低线程的创建和销毁!此时就会使用线程池这种池化技术!
2、三大方法(创建线程池的方法)
ExecutorService ThreadPool1 = Executors.newSingleThreadExecutor();// 单个线程
ExecutorService ThreadPool2 = Executors.newFixedThreadPool(5); // 创建一个固定的线程池的大小
ExecutorService ThreadPool3 = Executors.newCachedThreadPool(); // 可伸缩的,遇强则强,遇弱则弱
//工作中用自定义线程池方法
ExecutorService ThreadPool1 = new ThreadPoolExecutor(
2,//核心线程池大小
5,//最大线程池大小
3,//超时了没有人用就会释放
TimeUnit.SECONDS,//释放时间超时单位
new LinkedBlockingDeque<>(3), //阻塞队列
Executors.defaultThreadFactory(),//线程工厂
new ThreadPoolExecutor.AbortPolicy());//拒绝策略
用完线程池之后一定要关闭线程池
ThreadPool3.shutdown();
3、七大参数(自定义线程池:推荐)
底层都是返回一个new 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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
最大线程如何设置?
int maximumPoolSize——最大线程池大小 ! 调优!
- CPU密集型,CPU是几核,就在最大线程池数量定义为几,可以用Runtime.getRuntime().availableProcessors();判断
- IO密集型,判断程序中十分耗IO的线程,大于改值即可
线程池业务逻辑!
- 多个线程同时进行时,首先获取核心线程池
- 如果核心线程池使用满了,下面的线程会进入阻塞队列等待
- 如果阻塞队列满了,则会开启最大线程池数量
- 如果最大线程池占用满了,阻塞队列满了,则会执行拒绝策略
- 如果线程执行完了超时没人用,最大线程数量释放,保留核心线程数量
5、四种拒绝策略(线程超量处理方法)
java new ThreadPoolExecutor.AbortPolicy()//如果线程超量则抛出异常
new ThreadPoolExecutor.CallerRunsPolicy()//如果线程超量则在主线程执行
new ThreadPoolExecutor.DiscardOldestPolicy()//如果线程超量则丢掉任务,不会抛出异常
new ThreadPoolExecutor.DiscardPolicy()//如果线程超量则尝试竞争,丢掉任务,不会抛出异常