一、线程池介绍及优势
1、介绍
- 线程池做的工作主要是控制运行的线程的数量,在处理过程中将待执行的任务放到队列中,然后在线程创建后启动这些任务。如果要执行的任务超过了线程池最大线程数量,那么需要等待其他线程执行完,才能够去继续分配线程。
2、优势
主要特点:线程复用;控制最大并发数;管理线程
- 降低资源消耗。通过重复利用已创建的线程,降低线程创建和销毁的系统消耗
- 提高响应速度。当任务到达时,任务可以不用等到线程创建而使用已有的线程去执行任务
- 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进一步的分配、调优和监控
二、ThreadPoolExecutor参数详解
java提供了ThreadPoolExecutor这个类为我们自定义线程池,这个类的构造方法主要有7个参数。详解如下:
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;
}
下面将以银行柜台办理业务的流程说明线程池的的7大参数。
银行柜台情况说明如下:2个固定窗口,3个活动窗口,待客区10个位置
工作流程如下:
- 2个固定窗口接待客人,
- 客人多时,先坐在待客区,
- 如果待客区满了,开设活动窗口,活动窗口接待客人
- 如果固定窗口、待客区、活动窗口都排满了人,则通知新的客人,下次再来。
- 如果一段时间内没有客人了,撤掉活动窗口,由固定窗口继续接待客人。
1. corePoolSize:核心线程数,即2个固定窗口
2. maximumPoolSize:最大线程数,即2个固定窗口+3个活动窗口
3. keepAliveTime:空闲线程存活时间
4. TimeUnit:时间单位
5. workQueue:任务排队的队列,即待客区
6. threadFactory:创建线程的工厂
7. RejectedExecutionHandler:拒绝策略,有4种。<1>直接拒绝,返回异常<2>将提交的任务退回给主线程<3>丢弃队列中等待时间最长的任务<4>直接丢弃任务
即固定窗口、待客区、活动窗口都排满了人则通知新的客人,下次再来
三、juc提供的线程池
下面贴出了jdk提供给我们的线程池的源码。其实下面几种线程池都不介意使用,如果真的要使用的话还是自己手动去调用ThreadPoolExecutor的构造方法去
1、newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0,
2147483647,
60L,
TimeUnit.SECONDS,
new SynchronousQueue());
}
2、newFixedThreadPool
public static ExecutorService newFixedThreadPool(int var0) {
return new ThreadPoolExecutor(var0,
var0,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
3、newScheduledThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize,
Integer.MAX_VALUE,
0,
NANOSECONDS,
new DelayedWorkQueue());
}
4、newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1,
1,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
四、确定线程数
1、CPU密集型
如果线程多是用作cpu计算,此时线程可以设置为CPU个数+1。
2、IO密集型
有两种策略:
- 线程数为2*CPU个数
- CPU个数/(1-因子),因子一般为0.8~0.9之间