线程池的底层原理
作者:bin线程池的创建实际上都是同一个方法(ThreadPoolExecutor):
我们看他的变量:
corePoolSize : 核心线程数,即队列未满时,线程跑的数量
maximumPoolSize:最大线程数,即如果队列满了,可以将最大线程数加到多少
workQueue : 新建的线程等待队列
keepAliveTime : 线程的存活时间,即线程跑完任务后,多久被回收掉
threadFactory:线程工厂,用于创建线程
handler:队列满且达到最大核心线程数时,执行的拒绝策略
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue 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; }
线程池的状态:
//接受新任务并处理排队的任务 private static final int RUNNING = -1 << COUNT_BITS; //不接受新任务,但是处理排队的任务 private static final int SHUTDOWN = 0 << COUNT_BITS; //不接受新任务,不处理排队任务和中断进行中的任务 private static final int STOP = 1 << COUNT_BITS; //所有任务都被终止了,workerCount为0,为此状态时还将调用terminated()方法 private static final int TIDYING = 2 << COUNT_BITS; //terminated()已执行完成 private static final int TERMINATED = 3 << COUNT_BITS;
3种不同的队列:
SynchronousQueue(直接提交策略)
不会用队列取缓存任务,运行中的线程达到maximumPoolSize时,就无法新增任务,执行异常策略。
private static ExecutorService cachedThreadPool = new ThreadPoolExecutor( 4, 10, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), r -> new Thread(r, "ThreadTest"));
LinkedBlockingQueue(无界队列):达到maximumPoolSize时,就加入队列,因为是链表,会一直加,直到OOM,插入和拉取分别2个锁,因此linked读写效率会比array更高
private static ExecutorService cachedThreadPool = new ThreadPoolExecutor( 4, Runtime.getRuntime().availableProcessors() * 2, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(Integer.MAX_VALUE), r -> new Thread(r, "ThreadTest") );
ArrayBlockingQueue(有界限队列):运行线程数达到corePoolSize时,加入队列,队列达到最大时,添加新线程,插入和拉取使用相同但锁,达到maximumPoolSize时,采取拒绝策略
是数组有界,LinkedBlockingQueue是链表无界,但link要注意不要内存溢出。
private static ExecutorService cachedThreadPool = new ThreadPoolExecutor( 4, Runtime.getRuntime().availableProcessors() * 2, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(32), r -> new Thread(r, "ThreadTest"));