public static void main(String[] args) throws Exception{
int corePoolSize = 5;
int maximumPoolSize = 10;
int blockingQueueSize = 13;
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
corePoolSize, //最小线程数
maximumPoolSize, //最大线程数
100, TimeUnit.MILLISECONDS, //超过最小线程数的线程,空闲多久则回收
new ArrayBlockingQueue<>(blockingQueueSize, true)//放到某个队列里
);
//是否去掉非活动线程
threadPoolExecutor.allowCoreThreadTimeOut(true);
//默认创建最小线程数的线程
threadPoolExecutor.prestartAllCoreThreads();
Set<Long> threadId = new HashSet<>();
long threadsStartTime = System.currentTimeMillis();
for (int i = 0; i < 20; i++) {
threadPoolExecutor.execute(() -> {
try {
long threadStartTime = System.currentTimeMillis();
Thread thread = Thread.currentThread();
long id = thread.getId();
long subTime = threadStartTime - threadsStartTime;
System.out.println("threadsStartTime:"+threadsStartTime+",threadStartTime:"+threadStartTime+",subTime:"+ subTime +",id:"+id);
Thread.sleep(3000);
if(threadId.contains(id)){
System.out.println("已存在的线程执行任务:"+id +":"+thread.getName());
}else{
threadId.add(id);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
System.in.read();
}
测试
- 创建20个任务,阻塞队列长度为18,线程池最小线程数为5,最大线程数为10
从上图可知,线程池创建了5个线程处理了5个任务,15个任务扔进了队列
- 创建20个任务,阻塞队列长度为13,线程池最小线程数为5,最大线程数为10
从上图可知,线程池创建了7个线程处理了7个任务,13个任务扔进了队列 - 创建20个任务,阻塞队列长度为9,线程池最小线程数为5,最大线程数为10
从上图可知,线程池创建了10个线程处理了10个任务,9个任务扔进了队列,一个任务被拒绝
源码分析
基于测试结果,应该对其执行过程有了初步的了解
execute(Runnable command)
/**
* Executes the given task sometime in the future. The task
* may execute in a new thread or in an existing pooled thread.
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
* the task is handled by the current {@code RejectedExecutionHandler}.
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
* {@code RejectedExecutionHandler}, if the task
* cannot be accepted for execution
* @throws NullPointerException if {@code command} is null
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
//如果线程池中线程数没有达到corePoolSize,则新增线程(worker)
if (addWorker(command, true))
return;
//更新c值。
c = ctl.get();
}
//线程池处于RUNNING状态,并且阻塞队列未满
//workQueue.offer(command)是非阻塞方法,当队列满时直接返回false(例如,SynchronousQueue如果没有线程在阻塞take,则返回false)
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//再次检查状态,如果发现不是RUNNING状态,则remove掉刚才offer的任务。
if (! isRunning(recheck) && remove(command))
reject(command);
//如果有效线程数==0,添加一个线程,而不去启动它。??
//怎么会==0?
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//如果不是RUNNING状态,或者阻塞队列已满,则添加线程
//如果不能添加,则reject。
//false 表示添加的线程属于maximumPoolSize,如果线程数已经达到maximumPoolSize,则reject
else if (!addWorker(command, false))
reject(command);
}
阻塞队列(BlockingQueue) 的一些操作方法
* | 抛出异常 | 特殊值 | 阻塞 | 超时 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | 不可用 | 不可用 |
addWorker(Runnable firstTask, boolean core)
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
//1. 处于 STOP, TYDING 或 TERMINATD 状态 并且
//2. 不是SUHTDOWN 或者 firsttask != null 或 queue不为空
return false;
for (;;) {
int wc = workerCountOf(c);
//wc大于最大容量。
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
//没有空余的线程了。
return false;
//有效线程数加一,加一成功后break
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
//runState改变,从头执行逻辑。
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
//else runState 没变,重新去执行加一操作。
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//创建worker
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
//添加成功,启动线程
//启动后执行runWorker(this);
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
runWorker(Worker w)
运行worker,该线程不断的getTask()从队列中获取任务,然后 task.run();运行。只要队列中有值则不断循环。
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//getTask()方法是个无限循环, 会从阻塞队列 workQueue中不断取出任务来执行.
//addWorker(null, false);情况,task==null,这样就需要getTask从队列中取任务执行(自己不带任务)。直到getTask返回null
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
//执行
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
getTask()
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
// STOP以上状态,或者SHUTDOWN状态下queue为空,即都没有任务要执行了。
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//线程数减一
decrementWorkerCount();
//该线程退出。
return null;
}
//下面都是RUNNING状态,或SHUTDOWN状态queue!=null
int wc = workerCountOf(c);
// Are workers subject to culling?
//设置了allowCoreThreadTimeOut,或者线程数大于core线程数。
//是否剔除超时的线程?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 通过返回 null 结束线程。
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
//线程已经准备好,正在take(),没有什么标志位?
//取出runnable 返回
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
结论
线程池执行任务流程
- 当线程数小于线程池的最小线程数时,会创建线程去执行任务
- 当线程池的线程数大于等于线程池的最小线程数时,如果线程池处于运行状态,且阻塞队列没满时,则将任务塞进队列
- 如果队列满时,但线程池的线程数小于最大线程数时,直接创建线程去处理任务
- 否则拒绝任务