我主要从以下几个部分来剖析一下ThreadPoolExecutor线程池的实现原理
1. 先拿个例子来讲解
2. 分析内部实现
3. 总结
1. 先拿个例子来讲解
我感觉看懂整个实现,最主要还是看懂整个执行过程,这样就不怕中间哪一步不懂了,举个例子吧
final int CORE_POOL_SIZE = 1;//核心线程数,后边解释这个变量
final int MAX_POOL_SIZE = 3;//最大允许的任务数,超过这个数目的话,就reject
ThreadFactory factory = Executors.defaultThreadFactory();//默认的线程产生工厂
ExecutorService exec = new CustomExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE,
5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1),
factory);
exec.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
exec.shutdown();
try {
while (!exec.awaitTermination(1, TimeUnit.SECONDS));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace(System.out);
}
这里的CustomExecutor是我复制了ThreadPoolExecutor的源代码,主要是方便调试跟踪,因为我发现我把jdk的源代码attach上去以后,在调试跟踪的时候,居然代码和调试的位置不对应。呐,调试代码最要紧的就是开心啦,调试很麻烦,这个大家都是不想的啦,TVB热语,大家不要扔鸡蛋,--^_^--
构造函数参数有这样5个,核心线程数,最大允许的任务数(说最大线程池数,我觉得不妥吧,如果有不对,请指教),时间,时间单位,队列(在当前处理的任务超过了CORE_POOL_SIZE的时候,任务会放进队列里去),产生线程的工厂。我这里设置的CORE_POOL_SIZE为1,MAX_POOL_SIZE为3,队列的长度为1,就是为了测试放入执行三个任务后是第三个任务会怎么执行的.如果在第一个任务没有执行完毕,即在小于CORE_POOL_SIZE的情况下,会调用addIfUnderCorePoolSize(command),什么意思呢?产生了一个工作线程来执行这个任务command呗,放入第二个任务会进去到队列workQueue.offer(command),因为CORE_POOL_SIZE为1,所以不能再执行任务了,只能将新来的任务暂存在队列中,再来一个任务---第三个任务则会调用addIfUnderMaximunPoolSize(command),这又是什么意思?就是说队列也满了,因为我们设置队列长度为1,所以就调用该函数,来创建一个新的工作线程来处理这个无法进入队列的任务,代码参考下面。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
好了,下面再详细讨论一下CORE_POOL_SIZE,MAX_POOL_SIZE,keepAliveTime,因为我觉得这个还是线程池好像都是围绕这几个变量打造的。
2. 分析内部实现
1. 当前的任务数小于corePoolSize
每新来一个任务,则会创建一个工作线程(worker)来处理当前的任务,worker在keepAliveTime的时间内
如果没有收到新的任务,则该worker会消失
这里比较玄妙的地方在以下的code:
private Thread addThread(Runnable firstTask) {
Worker w = new Worker(firstTask);
Thread t = threadFactory.newThread(w);
if (t != null) {
w.thread = t;
workers.add(w);
int nt = ++poolSize;
if (nt > largestPoolSize)
largestPoolSize = nt;
}
return t;
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
2. 当前的任务数大于等于corePoolSize
a. 放入到queue中,如果有工作线程空闲,即task为null时候,从队列中拿一个任务getTask(), r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
b. 当队列已经满的时候,则判断maxPoolSize是否小于当前的处理任务数以及等待的任务数注意,如果队列已经满的时候,则再来线程的话会先于队列中的任务而得到执行public void run() { try { System.out.println(Thread.currentThread().getName()); Runnable task = firstTask; firstTask = null; while (task != null || (task = getTask()) != null) { runTask(task); task = null; } } finally { workerDone(this); } } Runnable getTask() { for (;;) { try { int state = runState; if (state > SHUTDOWN) return null; Runnable r; if (state == SHUTDOWN) // Help drain queue r = workQueue.poll(); else if (poolSize > corePoolSize || allowCoreThreadTimeOut) r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS); else r = workQueue.take(); if (r != null) return r; if (workerCanExit()) { if (runState >= SHUTDOWN) // Wake up others interruptIdleWorkers(); return null; } // Else retry } catch (InterruptedException ie) { // On interruption, re-check runState } } }
private boolean addIfUnderMaximumPoolSize(Runnable firstTask) { Thread t = null; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { if (poolSize < maximumPoolSize && runState == RUNNING) t = addThread(firstTask); } finally { mainLock.unlock(); } if (t == null) return false; //执行会先于队列中的任务,然后这个新的工作线程(工作线程会随着新任务而产生,见addThread)执
//行完当前的任务以后,会去取队列中的线程 t.start(); return true; }
3. 总结
欢迎关注我的微博:http://weibo.com/stuckin