【Java并发】- 11.对Java提供的ThreadPoolExecutor线程池的深入刨析及相关实现源码的解析

1 线程池提交任务的源码分析

对于线程池来说,其提供了execute与submit两种方式来向线程池提交任务

总体来说,submit方法是可以取代execute方法的,因为它既可以接收Callable任务,也可以接收Runnable任务。

关于线程池的总体执行策略:

  1. 如果线程池中正在执行的线程数 < corePoolSize,那么线程池就会优先选择创建新的线程而非将提交的任务加到阻塞队列中。
  2. 如果线程池中正在执行的线程数 >= corePoolSize,那么线程池就会优先选择对提交的任务进行阻塞排队而非创建新的线程。
  3. 如果提交的任务无法加入到阻塞队列当中,那么线程池就会创建新的线程;如果创建的线程数超过了maximumPoolSize,那么拒绝策略就会起作用。
1.1 submit(Callable task)方法
//这个方法在ThreadPoolExecutor的父类AbstractExecutorService中的方法
public <T> Future<T> submit(Callable<T> task) {
	//空指针判断
    if (task == null) throw new NullPointerException();
    //完成了成员变量,和相关属性的设定,并构造了FutureTask对象
    RunnableFuture<T> ftask = newTaskFor(task);
    //使用execute执行任务。
    execute(ftask);
    return ftask;
}

//RunnableFuture接口,将任务的运行Runnable和任务执行结果Future组装在一起。
//当执行run方法后执行的结果会被封装在Future中
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

//这个方法只为了构造出来一个FutureTask
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

//该方法就只是把callable对象赋值,且把线程状态设置为NEW = 0.
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

//是一个可取消的异步的计算,提供了对Future基本的实现。
public class FutureTask<V> implements RunnableFuture<V>

可以看到,尽管submit方法与execute方法的接收任务的类型不同,但是submit方法最终还是调用了execute方法去执行任务。不过submit对任务进行了封装使得execute在执行完任务后可用获取执行任务的return的结果。

1.2 submit(Runnable task)方法和submit(Runnable task, T result)方法

这两个方法传入的任务类型相同故,放在一起讲。

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task, result);
    execute(ftask);
    return ftask;
}

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}
//将Runnable对象转换为一个callable对象,经历这一系列转换后,这个方法和
//submit(Callable<T> task)方法的执行就相同了。
public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}

/**
 * A callable that runs given task and returns given result
 */
 //这个类真正意义上实现了Runnable对象转换为一个callable对象
static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    //调用call方法时内部直接调用了run方法
    //这里的result就是直接调用submit(Runnable task, T result)
    //方法时传入的result,不过submit(Runnable task)将result置为
    //null,所以之后submit(Runnable task)执行后收不到结果
    //不过在整个过程中并没有对result的值进行任何的改变,这个值
    //在一开始就是固定的
    public T call() {
        task.run();
        return result;
    }
}

可以看到两个方法最终都调用了newTaskFor构造了一个FutureTask,不过

  • submit(Runnable task) :方法将result参数置为null传入,使该方法执行任务的结果,不会通过result对象得到。
  • submit(Runnable task, T result) :是将result参数传入的,不过传入的result参数结果是固定的,传入的result是什么,最后得到的就是什么。

通过上述分析我们可知submit(Runnable task) 只是 submit(Runnable task, T result) 方法的一个特例。而这两个方法传入的Runnable对象最终会换为一个callable对象,转换为与submit(Callable task) 方法相同的形式。而这三个方法最后都是通过execute

1.3 线程池的状态分析(为了更好的理解execute先讲这个)

对于线程池来说,存在两个状态需要维护:

  1. 线程池本身的状态:ctl的高3位来表示
  2. 线程池中所运行着的线程的数量:ctl的其余29位来表示
线程池中的5种状态

线程池一共存在5种状态:

  1. RUNNING:线程池可以接收新的任务提交,并且还可以正常处理阻塞队列中的任务。
  2. SHUTDOWN:不再接收新的任务提交,不过线程池可以继续处理阻塞队列中的任务。
  3. STOP:不再接收新的任务,同时还会丢弃阻塞队列中的既有任务;此外,它还会中断正在处理中的任务。
  4. TIDYING:所有的任务都执行完毕后(同时也涵盖了阻塞队列中的任务),当前线程池中的活动的线程数量降为0,将会调用terminated方法。
  5. TERMINATED:线程池的终止状态, 当terminated方法执行完毕后,线程池将会处于该状态之下。
线程池中状态的转移
  • RUNNING -> SHUTDOWN:当调用了线程池的shutdown方法时,或者当finalize方法被隐式调用后(该方法内部会调用shutdown方法)
  • RUNNING, SHUTDOWN -> STOP:当调用了线程池的shutdownNow方法时
  • SHUTDOWN -> TIDYING:在线程池与阻塞队列均变为空时
  • STOP -> TIDYING:在线程池变为空时
  • TIDYING -> TERMINATED:在terminated方法被执行完毕时
1.4 execute(Runnable command) 方法

线程池对任务的执行最终是由这个方法实现的,下面就对这个方法进行具体的分析。

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.
     *
     //线程数少于corePoolSize会尝试开启一个新的线程来执行任务addWorker方法
     //会做一些同步处理

     * 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();
    //workerCountOf获取已经在线程池中存在的线程数量
    //如果判断为true会按照第一种流程执行任务
    if (workerCountOf(c) < corePoolSize) {
    	//尝试创建一个新的线程并且把传入的任务当成该线程的第一个
    	//任务去执行
        if (addWorker(command, true))
            return;
        //创建新的线程去执行任务失败,再次获取ctl(这个值可能被其他线程修改)
        c = ctl.get();
    }
    //此时说明存在的线程数大于或等于corePoolSize,尝试入队操作
    //或虽然线程数少于corePoolSize但是提交任务失败
    if (isRunning(c) && workQueue.offer(command)) {
    //此时线程池正在运行且任务插入队列成功
    	//再次获取ctl的值
        int recheck = ctl.get();
        //再次判断,如果线程池不再运行,就将刚才存入阻塞队列的任务移除出阻塞队列
        //并且调用reject拒绝策略处理任务
        if (! isRunning(recheck) && remove(command))
            reject(command);
        //此时线程池正在运行,判断线程池中线程数量是否等于0
        //如果等于0,调用addWorker创建新的线程执行任务
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    //执行到这说明线程池被关闭,创建新的线程执行任务,如果失败则
   //执行拒绝策略
    else if (!addWorker(command, false))
        reject(command);
}

这个方法会在某一个时间执行任务,可能使用新建的线程,也可能使用线程池中已经存在的线程。如果任务不能被提交执行或线程池已经被关闭,或者阻塞队列已满不能存放新的任务,任务会被拒绝执行处理器接管。

2 线程池添加线程的方法addWorker


//firstTask:传入的任务有两种情况:
//1.如果线程数小于corePoolSize就会创建新的线程执行任务
//2.如果阻塞队列已满也会创建新的线程执行任务

//core:true使用corePoolSize作为线程创建的边界
//false:使用maximumPoolSize作为线程数的边界
private boolean addWorker(Runnable firstTask, boolean core) {
	//标签,可通过break等用法直接从后面的代码跳到此处开始执行
    retry:
    for (;;) {
        int c = ctl.get();
        //runStateOf获取线程池的状态
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        //线程池的状态为shutdown或跟高的状态,且队列为空,
        //说明不能创建线程了
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

		//到这说明线程池正在运行,可以创建线程
        for (;;) {
        	//workerCountOf获取已有线程的数量
            int wc = workerCountOf(c);
            //如果线程数大于CAPACITY(最大可以创建线程数量)
            //或者到了线程创建的数量边界,就才能在创建线程,
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
                //尝试对线程数加1,成功在跳到retry
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            //再次检查线程池状态
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

	//上面的代码仅仅是完成了对线程数量的加一操作、
	//执行到这说明线程数加一成功可以开始创建线程了

    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();
                   //线程池正常运行且worker创建的没有运行
                   //把线程放入workers,这个workers是一个HashSet
                   //用来维护所以线程池中的线程
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    //置为true表示线程已经被成功放入workers集合
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            //线程添加成功可以开始运行线
            if (workerAdded) {
                t.start();
                //线程成功启动
                workerStarted = true;
            }
        }
    } finally {
    //线程启动失败,把所有参数回滚到addWorker方法执行前的状态。
        if (! workerStarted)
            addWorkerFailed(w);
    }
    //workerStarted = true;表示线程添加到workers集合且
    //成功执行,否则为false表示所有参数没有变化
    return workerStarted;
}

/**
 * Creates with given first task and thread from ThreadFactory.
 * @param firstTask the first task (null if none)
 */
 //创建新的线程执行任务
Worker(Runnable firstTask) {
	//Worker是一个AQS子类,state置为-1是保证在创建过程中线程不会的打断
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    //在创建线程时会将Worker对象自生传入因为worker实现了Runnable
    this.thread = getThreadFactory().newThread(this);
}

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable

//回滚所有属性的状态
private void addWorkerFailed(Worker w) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        if (w != null)
        //把创建的worker对象从workers集合中移除
            workers.remove(w);
        //对线程池存在的线程数减一
        decrementWorkerCount();
        //尝试终止线程池
        tryTerminate();
    } finally {
        mainLock.unlock();
    }
}

检查一个新的work(对线程的包装)是否能添加进来,如果添加成功worker count(线程总数)就会进行调整,且一个新的work就会被创建且启动运行firstTask就是我们传入的任务。

如果线程池处于shutdownstop状态吗,这个方法会返回false,或者线程工厂无法 创建一个新的线程(线程工厂返回null或创建线程出现异常,如OOM异常)。就会对任务进行回滚把任务的状态恢复到一个最初的状态。

addWorker方法在线程创建成功后会调用t.start(); worker对象中的thread对象的start() 方法,而这个thread对象传入的RunnableWorker,故在调用t.start(); 时会调用workerrun方法。

public void run() {
    runWorker(this);
}

run方法调用了**runWorker(this)**方法可知这个方法就是最终执行任务的方法。

3 runWorker(this):真正执行任务的方法

/**
 * Main worker run loop.  Repeatedly gets tasks from queue and
 * executes them, while coping with a number of issues:
 *
 * 1. We may start out with an initial task, in which case we
 * don't need to get the first one. Otherwise, as long as pool is
 * running, we get tasks from getTask. If it returns null then the
 * worker exits due to changed pool state or configuration
 * parameters.  Other exits result from exception throws in
 * external code, in which case completedAbruptly holds, which
 * usually leads processWorkerExit to replace this thread.
 *
 * 2. Before running any task, the lock is acquired to prevent
 * other pool interrupts while the task is executing, and then we
 * ensure that unless pool is stopping, this thread does not have
 * its interrupt set.
 *
 * 3. Each task run is preceded by a call to beforeExecute, which
 * might throw an exception, in which case we cause thread to die
 * (breaking loop with completedAbruptly true) without processing
 * the task.
 *
 * 4. Assuming beforeExecute completes normally, we run the task,
 * gathering any of its thrown exceptions to send to afterExecute.
 * We separately handle RuntimeException, Error (both of which the
 * specs guarantee that we trap) and arbitrary Throwables.
 * Because we cannot rethrow Throwables within Runnable.run, we
 * wrap them within Errors on the way out (to the thread's
 * UncaughtExceptionHandler).  Any thrown exception also
 * conservatively causes thread to die.
 *
 * 5. After task.run completes, we call afterExecute, which may
 * also throw an exception, which will also cause thread to
 * die. According to JLS Sec 14.20, this exception is the one that
 * will be in effect even if task.run throws.
 *
 * The net effect of the exception mechanics is that afterExecute
 * and the thread's UncaughtExceptionHandler have as accurate
 * information as we can provide about any problems encountered by
 * user code.
 *
 * @param w the worker
 */
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    //firstTask是创建线程时传入的线程的第一个
    //Task任务对象即addWorker的Runnable firstTask参数
    //当然有可能为空,因为addWorker方法调用这个方法时
    //有几次都没有传入具体参数,而是传入null
    Runnable task = w.firstTask;
    w.firstTask = null;
    //解锁因为在创建worker时将worker(worker是一个AQS)的state
    //设置为-1,故想要正常执行需要把state设置为>=0,而unlock().在
    //执行的过程中会把state设置为0,让线程可以正常执行
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
    	//如果task不为null,说明创建worker对象时给了任务Task,故
    	//task != null判断为true,短路,就不会执行后续的task = getTask()

		//如果task为null判断task != null为false,需要获取task,故执行后续的
		//task = getTask()获取任务task
        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判断是判断线程池是否处于shutdown或比shutdown
            //更大的状态,如果是就要打断线程的执行
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
            	//在真正执行任务之前执行的处理
            	//ThreadPoolExecutor没有对其做任何处理
				// **这里使用了模板设计模式,父类设计了一个模板
				//却没有给出任何具体的实现,这些实现交由具体
				//工程的子类来实现**
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                	//执行任务
                	//这个run方法就是我们在代码中显式传入的要执行的内容
                    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 {
                //在真正执行任务之后执行的处理
            	//ThreadPoolExecutor没有对其做任何处理
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                //增加线程处理任务数,最后做统计用
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
    	//处理工作线程退出
    	//执行到这里正常情况说明线程池的阻塞队列已经为空,没有元素了
    	//所以要把工作线程停止
    	//如果completedAbruptly = true;说明处理task中发生异常也要对work进行处理
        processWorkerExit(w, completedAbruptly);
    }
}

//用来处理worker
//completedAbruptly为false说明线程池中所有任务执行完成
//true表示在处理task中发生异常
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        decrementWorkerCount();

    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
    	//做统计把w处理的任务数加到全部的处理任务数中
        completedTaskCount += w.completedTasks;
        //移除w
        workers.remove(w);
    } finally {
        mainLock.unlock();
    }

	//尝试设置线程池为Terminate
    tryTerminate();

    int c = ctl.get();
    //runStateLessThan看看线程池状态是否比stop低,低说明线程池还在正常运行
    if (runStateLessThan(c, STOP)) {
        if (!completedAbruptly) {
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }
        //如果上述判断通过说明线程池需要创建新的线程,那么就创建一个新的线程
        addWorker(null, false);
    }
}
3.1 getTask():获取阻塞队列中队头元素

从阻塞队列中获取第一个元素,如果返回null,则worker必须退出,且执行的线程数减一

    /**
     * Performs blocking or timed wait for a task, depending on
     * current configuration settings, or returns null if this worker
     * must exit because of any of:
     * 1. There are more than maximumPoolSize workers (due to
     *    a call to setMaximumPoolSize).
     * 2. The pool is stopped.
     * 3. The pool is shutdown and the queue is empty.
     * 4. This worker timed out waiting for a task, and timed-out
     *    workers are subject to termination (that is,
     *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
     *    both before and after the timed wait, and if the queue is
     *    non-empty, this worker is not the last thread in the pool.
     *
     * @return task, or null if the worker must exit, in which case
     *         workerCount is decremented
     */
    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.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    //task获取阻塞队列第一个元素,如果阻塞会等待,直到获取
                    //头元素,会队列为空获取一个null
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

4 关闭线程池的方法源码解析

4.1 shutdown()方法

shutdown()会修改线程池的状态。为shutdown使线程不再接收新的任务,而把新的任务交由拒绝策略处理。 然后关闭线程池中空闲的线程,当线程池中所有任务执行完成后(正在执行线程执行的任务和阻塞队列中的任务),才在真正的关闭线程池。

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
    	//执行权限的检查,因为有可能在运行过程中,线程的权限被改变,导致无法
    	//对线程池进行操作
        checkShutdownAccess();
        //把线程池置为shutdown状态
        advanceRunState(SHUTDOWN);
        //中断线程池中空闲的线程
        interruptIdleWorkers();
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    //把线程池设置为Terminate状态,到这一步线程池才真正被关闭
    tryTerminate();
}

//检查线程的执行权限,根据SecurityManager
private void checkShutdownAccess() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkPermission(shutdownPerm);
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers)
                security.checkAccess(w.thread);
        } finally {
            mainLock.unlock();
        }
    }
}

//更改线程池状态
private void advanceRunState(int targetState) {
    for (;;) {
        int c = ctl.get();
        //检查当前线程状态是否小于要修改的状态,如果满足
        //就使用CAS修改线程池的状态
        if (runStateAtLeast(c, targetState) ||
            ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
            break;
    }
}

//中断线程池在空闲的线程
private void interruptIdleWorkers() {
    interruptIdleWorkers(false);
}
//中断线程池在空闲的线程,这是真正执行中断逻辑的带码
private void interruptIdleWorkers(boolean onlyOne) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
    	//workers创建线程池中的线程时说过,这个workers管理
    	//所有线程池中的线程
        for (Worker w : workers) {
            Thread t = w.thread;
            //!t.isInterrupted()判断线程是否是被中断的,如果是就不需要再次中断
            //w.tryLock():检查当前线程是否正在执行,在分析线程执行任务的代码时
            //线程在执行任务时会加锁,如果tryLock成功说明线程处于空闲状态
            if (!t.isInterrupted() && w.tryLock()) {
                try {
                	//将线程池中处于空闲状态的线程打断
                    t.interrupt();
                } catch (SecurityException ignore) {
                } finally {
                    w.unlock();
                }
            }
            if (onlyOne)
                break;
        }
    } finally {
        mainLock.unlock();
    }
}

//最终关闭线程池的方法
final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        if (workerCountOf(c) != 0) { // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    terminated();
                } finally {
                    ctl.set(ctlOf(TERMINATED, 0));
                    //之前的代码就是主要线程池的状态设置为Terminate
                    //这里不再过多的解析,
                    
                    //termination.signalAll();唤醒所有阻塞在
                    //Terminate对象上的线程,处理其逻辑
                    //完成线程池的最终清理
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}
4.2 shutdownNow()方法

shutdownNow()方法比shutdown()更粗暴,它虽然也是对后续的任务执行拒绝策略,但是对线程池中的线程,无论是空闲还是正在运行的都会打断。然后关闭线程池。

shutdownNow()会返回线程池的阻塞队列中所有未执行任务的集合

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
    	//检查执行权限
        checkShutdownAccess();
        //设置线程状态
        advanceRunState(STOP);
        //打断线程池中的线程
        interruptWorkers();
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    //清理线程池所有的资源,然后关闭线程池
    tryTerminate();
    return tasks;
}

//打断已经start的线程
private void interruptWorkers() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
    	//从worker获取所有线程包装的worker对象
    	//并且如果线程正在执行则把线程打断
        for (Worker w : workers)
            w.interruptIfStarted();
    } finally {
        mainLock.unlock();
    }
}
//打断线程的逻辑,只要线程是start且未被打断的就打断线程的执行
void interruptIfStarted() {
    Thread t;
    if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
        try {
            t.interrupt();
        } catch (SecurityException ignore) {
        }
    }
}

5 使用ThreadPoolExecutor线程池提供的默认方法存在的隐患

之前讲过使用submit()方法提交Callable类型任务的时候,会生成一个新的FutureTask

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

这个task会交于execute执行,此时ftask的状态为NEW
ftask会作为线程的执行结果返回

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}

FutureTask中的state等级

    private volatile int state;
    private static final int NEW          = 0;
    private static final int COMPLETING   = 1;
    private static final int NORMAL       = 2;
    private static final int EXCEPTIONAL  = 3;
    private static final int CANCELLED    = 4;
    private static final int INTERRUPTING = 5;
    private static final int INTERRUPTED  = 6;

,而交由execute的任务,如果在线程池阻塞队列已满且线程数达到maximnuPoolSize时,将任务交由拒绝策略处理,而如果采用的拒绝策略是DiscardPolicy那么就不会对ftask做任何处理。

而在以上的情况下调用

Future submit = pool.submit(new CallTest());
System.out.println("这是执行的返回结果:" + submit.get() + "  序号为:" + integer.incrementAndGet());

而Future(返回的FutureTask对象) 的get方法处理逻辑为

//
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        s = awaitDone(false, 0L);
    return report(s);
}

可以看到如果状态小于COMPLETING,就会陷入等待状态。此时就会有一个问题上述的任务如果被线程池拒绝处理,那么其FutureTask的状态会一直保持NEW(0),那么在其返回FutureTask调用get()方法会一直阻塞导致程序出错。当然如果使用get(long timeout, TimeUnit unit)就不会发生上述问题。

题出这个问题是为了说明,在我们项目使用线程池时,应该自定义Java提供的线程池的许多类,因为Java提供的只是一个模板供我们参考,线程池是如果使用的,但是Java也预留许多接口供我们实现,如果贪图简便,直接使用Java提供的线程池,那么在具体任务是可能会发生,错误,导致程序异常执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值