从ThreadPoolExecutor源码理解线程池

线程池的状态:

线程有五种状态:新建,就绪,运行,阻塞,死亡,线程池同样有五种状态:RUNNING, SHUTDOWN, STOP, TIDYING, TERMINATED。

RUNNING:处于RUNNING状态的线程池能够接受新任务,以及对新添加的任务进行处理。

SHUTDOWN:处于SHUTDOWN状态的线程池不可以接受新任务,但是可以对已添加的任务进行处理。

STOP:处于STOP状态的线程池不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。

TIDYING:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。

TERMINATED:线程池彻底终止的状态。

 

ThreadPoolExecutor的execute方法:(来到线程池的线程会被封装成ThreadPoolExecutor.Worker对象,Worker也是实现类Runnable接口的,所以它本身也是一个线程)

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();//执行1
        if (workerCountOf(c) < corePoolSize) {//执行2
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {//执行3
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))//执行4
                reject(command);
            else if (workerCountOf(recheck) == 0)//执行5
                addWorker(null, false);
        }
        else if (!addWorker(command, false))//执行6
            reject(command);
}

代码的具体流程:

  1. 获取线程池的状态。
  2. 如果线程池当前线程数小于corePoolSize,则调用addWorker创建新线程执行任务,成功返回true,失败执行步骤3。
  3. 如果线程池处于RUNNING状态,则尝试加入阻塞队列,如果加入阻塞队列成功,则尝试进行Double Check,如果加入失败,则执行步骤4。
  4. 如果线程池变为了非RUNNING状态就需要从阻塞队列中移除队列,并调用reject()方法运行相应的拒绝策略。
  5. 如果当前线程池为空就新创建一个线程并执行
  6. 如果第三步判断为非运行状态,尝试新建线程,如果失败则执行拒绝策略。

在步骤2中如果加入阻塞队列成功了,则会进行一个Double Check的过程。Double Check过程的主要目的是判断加入到阻塞队里中的线程是否可以被执行。如果线程池不是RUNNING状态,则调用remove()方法从阻塞队列中删除该任务,然后调用reject()方法处理任务。否则需要确保还有线程执行。

posted @ 2019-05-30 12:25  LeeJuly  阅读(177)  评论(0)    收藏  举报