Java线程池
通过Executors创建线程池的时候调用newFixedThreadPool方法,继承的大概结构如下:
创建完成之后,线程池的结构如下:
在创建完线程池之后就可以调用execute方法来执行给定的Runnable了,具体的代码如下:
1 public void execute(Runnable command) { 2 if (command == null) 3 throw new NullPointerException(); 4 if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) { 5 if (runState == RUNNING && workQueue.offer(command)) { 6 if (runState != RUNNING || poolSize == 0) 7 ensureQueuedTaskHandled(command); 8 } 9 else if (!addIfUnderMaximumPoolSize(command)) 10 reject(command); 11 } 12 }
执行的流程还是很简单的,大致如下:
看到这里,把任务加入到了任务队列里面了,那么怎么运行这个方法呢?
在前面用C也些过一个线程池,同样是不断地循环去检查任务队列中是否有任务需要执行,有?从中取出来执行,这样该线程执行的代码段就改变了,变成设置的方法。如果发现任务队列中没有了多余的任务了,那么对应Worker的run方法中while循环也就该结束了,这样这个线程就消失了。run方法的代码如下:
1 public void run() { 2 try { 3 Runnable task = firstTask; 4 firstTask = null; 5 while (task != null || (task = getTask()) != null) { 6 runTask(task); 7 task = null; 8 } 9 } finally { 10 workerDone(this); 11 } 12 }
大致的执行流程如下:
上面这个流程中最关键的是runTask,但是第一句就让人不明白了,runState<STOP和runState>=STOP不是矛盾的么?首先看一下线程池的各个状态的含义:
- RUNNING=0,还可以接受新的任务;
- SHUTDOWN=1,不会再接受新任务,但是会把现有的任务执行完;
- STOP=2,所有的任务都完成了并处在中断状态;
- TERMINATED=3,所有的任务完成并且线程也都推出了;
如果runState<STOP成立,说明还有线程正在运行,也就是该条件为ture,然后就会执行Thread.interrupted()方法,该方法检查当前的线程是否正在中断状态,如果是中断状态的话返回true,否则返回false,如果runState>=STOP的话说明处于中断状态时正常的,让它继续处于中断状态,否则该函数清除掉了线程的中断状态。
beforeExecute预先执行以确保Runnable在Thread中。
然后task.run()方法可以像调用普通方法那样使得给定的代码得以执行。
afterExecute在方法运行没有发生异常或错误的时候才会执行,貌似是记录了一下运行时间的日志。
在一个Worker发现任务队列中没有多余的任务来执行的时候,while循环也就结束了,这时候就会调用方法workerDone,在该方法中更新统计信息:
1 void workerDone(Worker w) { 2 final ReentrantLock mainLock = this.mainLock; 3 mainLock.lock(); 4 try { 5 completedTaskCount += w.completedTasks; 6 workers.remove(w); 7 if (--poolSize == 0) 8 tryTerminate(); 9 } finally { 10 mainLock.unlock(); 11 } 12 }
上面是对最简单的线程池执行的流程。
-------------------------------------------
个人理解,欢迎拍砖。