JUC源码分析-ThreadPool-jdk6

蓝咒 提交于 2020-01-23 16:06:42

ThreadPool源码分析-jdk6

execute方法分析

public void execute(Runnable command) {

if (command == null)

throw new NullPointerException();

//poolSize初始值为0,先启动corePoolSize数量的线程执行

if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {

//poolSize==corePoolSize 后 将task加入队列

if (runState == RUNNING && workQueue.offer(command)) {

if (runState != RUNNING || poolSize == 0)

ensureQueuedTaskHandled(command);

}

//如果队列容量不够 且 poolSize < maximumPoolSize 则直接启动

else if (!addIfUnderMaximumPoolSize(command))

reject(command); // is shutdown or saturated

}

}

 

 

private boolean addIfUnderCorePoolSize(Runnable firstTask) {

Thread t = null;

final ReentrantLock mainLock = this.mainLock;

//下面代码中有根据共享变量判断的处理,为了防止并发问题,此处加锁。

mainLock.lock();

try {

if (poolSize < corePoolSize && runState == RUNNING)

//增加一个新的线程启动并执行任务

//此处重要

t = addThread(firstTask);

} finally {

mainLock.unlock();

}

return t != null;

}

private Thread addThread(Runnable firstTask) {

 

Worker w = new Worker(firstTask);

Thread t = threadFactory.newThread(w);

boolean workerStarted = false;

if (t != null) {

if (t.isAlive()) // precheck that t is startable

throw new IllegalThreadStateException();

w.thread = t;

workers.add(w);

int nt = ++poolSize;//工作线程将启动 增加工作线程数。

if (nt > largestPoolSize)

largestPoolSize = nt;

try {

//这里启动提交的任务

//重点是worker 的run实现

t.start();

workerStarted = true;

}

finally {

if (!workerStarted)

workers.remove(w);

}

}

return t;

}

下面看一下worker的重要方法

/**

* Main run loop

*/

//不断获取队列中的任务串行执行。

//其中 getTask(), runTask(task)是重要的方法

//while循环先执行执行提交的任务(addThread 中的 firstTask),然后从队列中取出任务执行

如果队列中无任务 则阻塞(依赖BlockingQueue的take()实现),直到取得一个任务为止。

public void run() {

try {

hasRun = true;

Runnable task = firstTask;

firstTask = null;

while (task != null || (task = getTask()) != null) {

runTask(task);//同步执行

task = null;

}

} finally {

//执行完成 --poolSize

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 void runTask(Runnable task) {

final ReentrantLock runLock = this.runLock;

//这里加锁 为修改 共享变量数据安全

runLock.lock();

try {

 

//如果不是stop状态 就要清除打断标识,保证当前线程后续阻塞执行不会被打断(Thread.interrupted()有返回打断状态,清除打断标识的作用

//如果是stop状态 就要保存打断状态,保证当前线程后续执行会被打断

if ((runState >= STOP ||

(Thread.interrupted() && runState >= STOP)) &&

hasRun)

thread.interrupt();

//跟踪执行状态确保afterExecute在任务完成后或执行任务中抛出异常后被调用

否则可能在执行afterExecute过程中抛出 runtime异常,这种情况我们不想再次执行它。(执行afterExecute的一个细致考虑。)

boolean ran = false;

//执行任务前和执行任务后都留了一个钩子

beforeExecute(thread, task);

try {

task.run();

ran = true;

afterExecute(task, null);

++completedTasks;

} catch (RuntimeException ex) {

if (!ran)

afterExecute(task, ex);

throw ex;

}

} finally {

runLock.unlock();

}

}

 

 

// poolSize < maximumPoolSize 则直接启动

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();

}

return t != null;

}

使用ExecutorService pool = Executors.newFixedThreadPool(2);

时的队列是LinkedBlockingQueue,其容量最大值是Integer.MAX_VALUE.

所以正常情况下不会将 queue装满,不会执行到addIfUnderMaximumPoolSize()

 

问题

queue什么时候能满

queue的大小需要看传入的queue的容量。

 

拒绝策略怎么执行

在任务数超过maximumPoolSize时根据传入的拒绝策略执行不同的处理

AbortPolicy: 中止策略,直接抛出异常 默认

AbortPolicyWithReport:写warn日志并抛出异常

CallerRunsPolicy:调用run方法策略,如果没有shutdown 则直接调用run方法。

DiscardPolicy:丢弃策略,什么都不做。

DiscardOldestPolicy:丢弃旧任务策略,丢弃旧任务,执行新任务。

NewThreadRunsPolicy:创建新线程执行策略,创建新线程执行,失败抛出异常。

 

shutdown(),shutdownNow源码分析

 

public void shutdown() {

SecurityManager security = System.getSecurityManager();

if (security != null)

security.checkPermission(shutdownPerm);

 

final ReentrantLock mainLock = this.mainLock;

mainLock.lock();

try {

if (security != null) { // Check if caller can modify our threads

for (Worker w : workers)

security.checkAccess(w.thread);

}

 

int state = runState;

if (state < SHUTDOWN)

runState = SHUTDOWN;

 

try {

for (Worker w : workers) {

//重点是这段

w.interruptIfIdle();

}

} catch (SecurityException se) { // Try to back out

runState = state;

// tryTerminate() here would be a no-op

throw se;

}

 

tryTerminate(); //如果线程池和队列为空执行终止处理

} finally {

mainLock.unlock();

}

}

 

/**

如果线程没有运行任务,就打断。

* Interrupts thread if not running a task.

*/

void interruptIfIdle() {

final ReentrantLock runLock = this.runLock;

if (runLock.tryLock()) {

//runLock 这个lock与runTask()用的是同一个,作用是等待任务执行完成

 

try {//hasRun在worker 中默认是false, 执行run方法后被赋值true

if (hasRun && thread != Thread.currentThread())

// 打断线程。getTask()做出相应处理

thread.interrupt();

 

} finally {

runLock.unlock();

}

}

}

//回头看run()和getTask()并结合对interrupt()分析

程序的运行会有两种情况

  1. 没有阻塞 正在运行中
  2. 执行到 getTask()的 r = workQueue.take(); 进入阻塞

情况1 最终会执行 getTask()的 r = workQueue.poll(); r=null,然后执行 workerDone(this);

情况2 抛出InterruptedException异常,在getTask中异常被捕获,进入循环,执行情况1的逻辑

 

重点代码注释如下:

Runnable getTask() {

for (;;) {

try {

int state = runState;

if (state > SHUTDOWN)

return null;

Runnable r;

if (state == SHUTDOWN) // Help drain queue

//当执行shutDown()后,run follow code,poll方法不会阻塞.

r = workQueue.poll();

else if (poolSize > corePoolSize || allowCoreThreadTimeOut)

//allowCoreThreadTimeOut 默认false,keepAliveTime是构造方法传进来的。线值程池类型是 cached的时候,值是60s

//当工作线程数超出核心线程数时,调用超时拉取方法。

r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);

else

//队列为空进入阻塞

r = workQueue.take();

if (r != null)

return r;

if (workerCanExit()) {//runState >= STOP 或队列为空 或运行核心线程timeout 且工作线程数据大于核心线程数

//其他的线程可能出于阻塞状态,用interrupt唤醒

if (runState >= SHUTDOWN) // Wake up others

interruptIdleWorkers();

return null;

}

// Else retry

} catch (InterruptedException ie) {

// On interruption, re-check runState

}

}

}

 

catch (InterruptedException ie)这段是容易忽略的地方。为了执行workQueue.take();进入阻塞状态的线程准备,保证能进入循环。

 

public void run() {

try {

hasRun = true;

Runnable task = firstTask;

firstTask = null;

// 通过task != null来控制是否终止循环。

while (task != null || (task = getTask()) != null) {

runTask(task);

task = null;

}

} finally {

workerDone(this);

}

}

}

//完成清理任务,如移除worker,执行队列中剩余的任务。

void workerDone(Worker w) {

final ReentrantLock mainLock = this.mainLock;

mainLock.lock();

try {

completedTaskCount += w.completedTasks;

workers.remove(w);

if (--poolSize == 0)

tryTerminate();

} finally {

mainLock.unlock();

}

}

//如果线程池和队列为空执行终止处理

private void tryTerminate() {

if (poolSize == 0) {

int state = runState;

//执行队列中剩余的任务

if (state < STOP && !workQueue.isEmpty()) {

state = RUNNING; // disable termination check below

//创建一个空任务的woker处理执行关闭期间添加进队列的任务,实现了拉灯处理

addThread(null);

}

//标识线程池位终止状态,解除termination的wait状态

if (state == STOP || state == SHUTDOWN) {

runState = TERMINATED;

termination.signalAll();

terminated();//目前是空实现

}

}

}

 

如果此时再添加任务,则不会被添加,执行拒绝策略

public void execute(Runnable command) {

if (command == null)

throw new NullPointerException();

if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {

//shutdown()执行后运行到这,shutdown状态 workQueue.offer(command)不执行

if (runState == RUNNING && workQueue.offer(command)) {

if (runState != RUNNING || poolSize == 0)

ensureQueuedTaskHandled(command);

}

//shutdown状态 不执行

else if (!addIfUnderMaximumPoolSize(command))

//执行拒绝策略

reject(command); // is shutdown or saturated

}

}

 

 

private boolean addIfUnderCorePoolSize(Runnable firstTask) {

Thread t = null;

final ReentrantLock mainLock = this.mainLock;

mainLock.lock();

try {

//shutdown状态 不执行

if (poolSize < corePoolSize && runState == RUNNING)

t = addThread(firstTask);

} finally {

mainLock.unlock();

}

return t != null;

}

 

shutdownNow 与shutdown不同之处

  1. runState is set to STOP,
  2. 所有工作线程被打断,不仅空闲的。
  3. 队列被耗尽,并返回。

public List<Runnable> shutdownNow() {

/*

* shutdownNow differs from shutdown only in that

* 1. runState is set to STOP,

* 2. all worker threads are interrupted, not just the idle ones, and

* 3. the queue is drained and returned.

*/

SecurityManager security = System.getSecurityManager();

if (security != null)

security.checkPermission(shutdownPerm);

 

final ReentrantLock mainLock = this.mainLock;

mainLock.lock();

try {

if (security != null) { // Check if caller can modify our threads

for (Worker w : workers)

security.checkAccess(w.thread);

}

 

int state = runState;

if (state < STOP)

runState = STOP;

 

try {

for (Worker w : workers) {

//不管是否是执行中,都调用打断。

w.interruptNow();

}

} catch (SecurityException se) { // Try to back out

runState = state;

// tryTerminate() here would be a no-op

throw se;

}

//耗尽并获取队列剩余任务

List<Runnable> tasks = drainQueue();

tryTerminate(); // Terminate now if pool and queue empty

return tasks;

} finally {

mainLock.unlock();

}

}

 

 

mainLock和runLock的作用?

runLock在runTask(Runnable task) 和interruptIfIdle()中使用,目的是为了interruptIfIdle不影响正在执行的任务。interruptNow 没有使用runlock,即使任务在执行,也打断。

//当改变poolSize, corePoolSize, maximumPoolSize, runState, and workers set.这些共享变量时,保证数据安全

private final ReentrantLock mainLock = new ReentrantLock();

Worker.thread?

Worker.thread 是新创建的线程

//创建代码如下

实现类:DefaultThreadFactory implements ThreadFactory

 

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;

}

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!