线程池
一、java原生线程池ThreadPoolExecutor
常用成员变量
//任务队列,当任务数量大于corePoolSize时会放入此队列中
private final BlockingQueue<Runnable> workQueue;
//线程工场负责创建线程实例
private volatile ThreadFactory threadFactory;
//拒绝策略 (CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy)
private volatile RejectedExecutionHandler handler;
//线程数量多于corePoolSize的部分空闲线程可以存在的时间
private volatile long keepAliveTime;
//核心线程数量
private volatile int corePoolSize;
//最大线程数量
private volatile int maximumPoolSize;
构造方法
1、采用默认的线程工场、默认的拒绝策略
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
2、采用默认的拒绝策略
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
3、采用默认的线程工场
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
4、全自定义构造方法
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;
}
阿里java手册要求使用此构造方法,从源码中可以看到当 corePoolSize < 0 || maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize || keepAliveTime < 0 时 会抛出 IllegalArgumentException 异常。
当 workQueue == null || threadFactory == null || handler == null 时 会抛出 NullPointerException 异常。
5、常用方法
-
execute(Runnable command)
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); //当工作线程小于核心线程时,启动新线程执行任务 if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } //线程数达到coreSize后,将任务放入队列里面 if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } //当队列被占满时,创建新的线程执行任务,直到线程数到达最大线程数,当三种条件都占满时,执行指定的拒绝策略 else if (!addWorker(command, false)) reject(command); }
-
每次提交任务时,如果线程数还没达到coreSize就创建新线程并绑定该任务。所以第coreSize次提交任务后线程总数必达到coreSize,不会重用之前的空闲线程。
-
线程数达到coreSize后,新增的任务就放到工作队列里,而线程池里的线程则努力的使用take()从工作队列里拉活来干。
-
如果队列是个有界队列,又如果线程池里的线程不能及时将任务取走,工作队列可能会满掉,插入任务就会失败,此时线程池就会紧急的再创建新的临时线程来补救。
-
临时线程使用poll(keepAliveTime,timeUnit)来从工作队列拉活,如果时候到了仍然两手空空没拉到活,表明它太闲了,就会被解雇掉。
-
如果core线程数+临时线程数 >maxSize,则不能再创建新的临时线程了,转头执行RejectExecutionHanlder。默认的AbortPolicy抛RejectedExecutionException异常,其他选择包括静默放弃当前任务(Discard),放弃工作队列里最老的任务(DisacardOldest),或由主线程来直接执行(CallerRuns).
根据上面的分析可以看到,当工作队列是一个无界队列时,线程池永远不会创建临时线程。
-
-
shutdown()
public void shutdown() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { checkShutdownAccess(); advanceRunState(SHUTDOWN); interruptIdleWorkers(); onShutdown(); // hook for ScheduledThreadPoolExecutor } finally { mainLock.unlock(); } tryTerminate(); }
-
shutdownNow()
-
isShutdown()