1. ThreadPoolExecutor线程池的七大参数
这里直接上ThreadPoolExecutor线程池构造器的源码
//1.corePoolSize-线程池中的核心线程数
//2.maximumPoolSize-线程池中允许的最大线程数,当核心线程数占满后,若最大线程数还未满,则启动非核心线程
//3.keepAliveTime-超时时间,当线程数大于核心线程数,这是多余线程也就是非核心线程在等待新任务的最长时间
//4.unit – keepAliveTime参数的时间单位
//5.workQueue-用于执行任务之前保存任务的队列,这个队列只保存Executor接口中execute提交的Runnable任务
//6.threadFactory-执行程序时创建线程的工厂
//7.handler-拒绝策略,当超过线程数或任务队列满了之后执行的拒绝策略
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;
}
理论上:当任务Runnable来时,会优先使用核心线程执行该任务,若核心线程都被使用,则新来的任务进入任务队列等待执行,若任务队列满了,则非核心线程执行该任务,若非核心线程也满了,若又有新任务来了,此时任务队列和线程数都满了,则执行拒绝策略
2. Executors.newCachedThreadPool()
Executors,JDK提供的一个创建线程池的类
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
CachedThreadPool线程池的核心线程数为0,最大线程数为2147483647,超时时间为60s,任务队列为SynchronousQueue
当达到一分钟, 未使用的线程将被终止并从缓存中删除,该线程池的任务队列SynchronousQueue为一个阻塞队列,没有容量,每个线程的插入操作都需要等待下一个线程的移除操作,类似用手传递东西,你不拿,东西就一直在上一个人手里,即来一个任务就创建一个非核心线程接收,然后放进缓存中,若超过60s,该线程未使用,则从缓存里删除。
3.Executors.newFixedThreadPool(int cpuCoreNum)
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
固定线程线程池,该线程的的最大线程数等于核心线程数,无超时时间,而任务队列LinkedBlockingQueue又是个未指定的边界的有界阻塞队列(默认容量为Integer.MAX_VALUE)基于链表实现的。 该队列对元素 FIFO(先进先出)进行排序。 队列的头部是在队列中停留时间最长的那个元素。 队列的尾部是在队列中停留时间最短的那个元素。由于该线程中的线程都是核心线程,即任务一来,核心线程执行该任务,核心线程一满,多余任务去LinkedBlockingQueue阻塞队列中等待执行,无超时时间,也就无拒绝策略。该线程池可以让任务并行执行(核心线程跑在CPU的内核上),多个核心线程即在不同的内核上并行执行。
补充:由于任务队列的不同,LinkedBlockingQueue的容量适合处理任务量多的场景而SynchronousQueue适合的场景较普遍,由于无容量,靠非核心线程执行然后缓存。
可以得出:
- 任务量平稳用–》FixedThreadPool
- 任务量不平稳用–》CacheThreadPool
4.Executors.newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
单一线程线程池,该线程池中的线程只有一个核心线程,无超视时间,任务队列也是有界的基于链表实现的阻塞队列,先进先出,让一个程序串行执行任务,保证了任务的执行顺序。
5.Executors.newScheduledThreadPool(int corePoolSize)
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
定时任务线程池,可指定核心线程数,最大线程数为2147483647,无超时时间,任务队列为延时队列,可以指定每个任务间隔多长时间执行,如:
public class TestScheduledThreadPool {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
/**
* 隔多长时间执行一次
*/
service.scheduleAtFixedRate(() -> {
try {
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
//initialDelay:第一个任务执行之前需要延迟多长时间,period:间隔多长时间
}, 0, 500, TimeUnit.MILLISECONDS);
}
}
6.后言
本文作为复习线程池时的知识整理,为了面试心里不慌。。