核心线程池的内部实现

核心的几个线程池,newFixedThreadPool(), newSingleThreadExecutor()和newCachedThreadPool()方法,内部实现都是使用了ThreadPoolExecutor()实现。

 public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {

    return new ThreadPoolExecutor(nThreads, nThreads,

                                  0L, TimeUnit.MILLISECONDS,

                                  new LinkedBlockingQueue<Runnable>(),

                                  threadFactory);

}

 

 public static ExecutorService newSingleThreadExecutor() {

    return new FinalizableDelegatedExecutorService

        (new ThreadPoolExecutor(1, 1,

                                0L, TimeUnit.MILLISECONDS,

                                new LinkedBlockingQueue<Runnable>()));

}

 

public static ExecutorService newCachedThreadPool() {

    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

                                  60L, TimeUnit.SECONDS,

                                  new SynchronousQueue<Runnable>());

}

 

ThreadPoolExecutor最重要的构造函数:

 

public ThreadPoolExecutor(

                          int corePoolSize,  //指定了线程池中线程数量

                          int maximumPoolSize, // 线程池中的最大线程数量

                          long keepAliveTime, // 当线程数量超过corePoolSize时,对于空闲线程的存活时间,即多余空闲线程多久会被销毁

                          TimeUnit unit,//keepAliveTime的单位

                          BlockingQueue<Runnable> workQueue,// 任务队列,被提交但尚未被执行的任务

                          ThreadFactory threadFactory, //线程工厂,用于创建线程,一般用默认的即可

                          RejectedExecutionHandler handler // 拒绝策略。当任务太多来不及处理,如何拒绝任务

)

workQueue是一个BlockingQueue接口的对象,仅用于存放Runnable对象;

所有BlockingQueue 都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互:

如果运行的线程少于 corePoolSize,则 Executor始终首选添加新的线程,而不进行排队。(如果当前运行的线程小于corePoolSize,则任务根本不会存放,添加到queue,而是直接抄家伙(thread)开始运行

如果运行的线程等于或多于 corePoolSize,则 Executor始终首选将请求加入队列而不添加新的线程

如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝

根据功能分类,可使用以下几种BlockingQueue:

 

  • 直接提交队列:该功能由SynchronousQueue对象提供。SynchronousQueue是一个特殊的BlockingQueue。SynchronousQueue没有容量,每一个插入操作都要等待一个相应的删除操作,反之,每一个删除操作都需要等待对应的插入操作。如果使用SynchronousQueue,提交的任务不会被真实的保存,而总是将新任务提交给线程执行,如果没有空闲线程,则尝试创建新的进程,如果进程数量已经达到最大值,则执行拒绝策略。因此,使用SynchronousQueue队列,通常要设置很大的maximumPoolSize,否则很容易执行拒绝策略。

  • 有界的任务队列:该功能可以使用ArrayBlockingQueue实现,ArrayBlockingQueue的构造函数必须带一个容量参数,表示队列的最大容量。当使用有界任务队列时,若有新的任务需要执行,如果线程池的实际线程数小于corePoolSize,则优先创建新的线程,若大于corePoolSize,则将任务加入等待队列。若等待队列已满,则在总线程数不大于maximumPoolSize的前提下,创建新的进程执行任务。若大雨maximumPoolSize,则执行拒绝策略。可见,有界任务队列,仅当任务队列装满时,才可能将线程数量提升到corePoolSize之上,换言之,除非系统任务非常繁忙,否则确保核心线程数维持在corePoolSize。

  • 无界任务队列:该功能可以通过LinkedBlockingQueue实现。与有界队列相比,除非系统资源耗尽,否则无界的任务队列不存在任务入队失败的情况。当有新的任务到来,系统线程数小于corePoolSize时,线程池会生成新的线程执行任务,仅当系统的线程数达到corePoolSize后,就不再继续增加。若后续有新任务加入,而又没有空闲的线程资源,则任务直接进入队列等待。若任务创建和处理速度差异很大,无界队列会保持快速增长,知道耗尽系统资源。

  • 优先任务队列:该队列是带有执行优先级的队列。他通过PriorityBlockingQueue实现,可以控制任务执行先后顺序。根据任务自身的优先级顺序执行,在确保系统性能的同时,也能有很好的质量保证(总是确保高优先级的任务先执行)。

 

ThreadPoolExecutor核心调度代码

 

在分析该类的execute方法前,先看这几个常量的值和一些方法的作用

 

1    /*

2     *  ctl的默认值为-536870912,

3     *  作用是将该值传入workerCountOf(int c)的参数c中,

4     *  则可以返回正在工作的线程数量

5     *  每当有一个线程加入工作,该值会加1

6     */

7     private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

8     private static final int COUNT_BITS = Integer.SIZE - 3;   //32-3=29

9     private static final int CAPACITY   = (1 << COUNT_BITS) - 1;//536870911

10                                                                          0001 1111 1111 1111 1111 1111 1111 1111

11     // runState is stored in the high-order bits,其中running<shutdown<stop<tidying<terminated

12     private static final int RUNNING    = -1 << COUNT_BITS;// -536870912

                                                                              1010 0000 0000 0000 0000 0000 0000 0000

13     private static final int SHUTDOWN   =  0 << COUNT_BITS;//0

                                                                              0000 0000 0000 0000 0000 0000 0000 0000

14     private static final int STOP       =  1 << COUNT_BITS;//536870912

                                                                              0010 0000 0000 0000 0000 0000 0000 0000

15     private static final int TIDYING    =  2 << COUNT_BITS;//1073741824

                                                                              0100 0000 0000 0000 0000 0000 0000 0000

16     private static final int TERMINATED =  3 << COUNT_BITS;//1610612736

                                                                              0110 0000 0000 0000 0000 0000 0000 0000

17

18     // Packing and unpacking ctl

19     private static int runStateOf(int c)     { return c & ~CAPACITY; }//当c<0时该方法返回的值为-536870912,否则为0

20     private static int workerCountOf(int c)  { return c & CAPACITY; }//获取工作线程数

21     private static int ctlOf(int rs, int wc) { return rs | wc; }//-536870912

execute

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.

     *

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

    if (workerCountOf(c) < corePoolSize) {

        if (addWorker(command, true))

            return;

        c = ctl.get();

    }

    if (isRunning(c) && workQueue.offer(command)) {

        int recheck = ctl.get();

        if (! isRunning(recheck) && remove(command))

            reject(command);

        else if (workerCountOf(recheck) == 0)

            addWorker(null, false);

    }

    else if (!addWorker(command, false))

        reject(command);

}

addWorker

1         private boolean addWorker(Runnable firstTask, boolean core) {

2         //外部循环

3         retry:

4         for (;;) {

5             int c = ctl.get();//获取当前工作线程数量,数量为{c-(-536870912)}

6            

7             int rs = runStateOf(c);//若c>=0时,该值才为0,否则该值一直为-536870912

8

9            

10             /*

11              *由上面的一些线程池状态常量值可知,running<shutdown<stop<tidying<terminated

12              *若rs>=shutdown,则表明线程池处于stop、tidying、terminated三种状态的一种

13              *若rs>=shutdown成立,则进行后面判断,

14              *1、线程池处于shutdown状态

15              *  1.1、firstTask不为null,则返回false,也即是线程池已经处于shutdown状态,还要添加新的线程,被直接驳回(拒绝)

16              *  1.2、firstTask为null

17              *     1.2.1、此时意味着线程池状态为shutdown状态,且first为null,若阻塞队列为空,则返回false

18              *2、线程处于大于shutdown的状态,则直接返回false

19             */

20             if (rs >= SHUTDOWN &&

21                 ! (rs == SHUTDOWN &&

22                    firstTask == null &&

23                    ! workQueue.isEmpty()))

24                 return false;

25             /*

26              *进入内循环以下两种情况会跳出该内循环,否则一直会循环

27              *1、当工作线程数量超过一定阈值,会直接返回false

28              *2、添加工作线程成功,即ctl的值进行了加一

29             */

30             for (;;) {

31                 int wc = workerCountOf(c);//获取工作线程的数量

32                 //当线程数量>=536870911或者>=corePoolSize或maximumPoolSize的时候,则返回false

33                 if (wc >= CAPACITY ||

34                     wc >= (core ? corePoolSize : maximumPoolSize))

35                     return false;

36                 if (compareAndIncrementWorkerCount(c))//使用unsafe的cas操作对ctl.get()的值进行加一

37                     break retry;//跳出这个外循环

38                 c = ctl.get();  // Re-read ctl

39                 if (runStateOf(c) != rs)//当此时的线程池状态和之前的状态不等时

40                     continue retry;//继续内循环  

41             }

42         }

43         //若进行到了此步操作,则表明工作线程数量加了1

44         boolean workerStarted = false;

45         boolean workerAdded = false;

46         Worker w = null;

47         try {

48             w = new Worker(firstTask);

49             final Thread t = w.thread;//该w.thread为worker内部新创建的thread

50             if (t != null) {

51                 final ReentrantLock mainLock = this.mainLock;

52                 mainLock.lock();//开启锁

53                 try {

54                     //获取锁后,再次获取线程池的状态

55                     int rs = runStateOf(ctl.get());

56                     /*

57                      *1、当线程池的状态处于shutdown以上状态,则直接释放锁,不启动线程,且执行addWorkerFailed方法

58                          执行该方法的作用是使工作线程数量-1

59                     */

60                     if (rs < SHUTDOWN ||

61                         (rs == SHUTDOWN && firstTask == null)) {

62                         if (t.isAlive()) // 创建的线程处于活跃状态,即被启动了,抛出异常

63                             throw new IllegalThreadStateException();

64                         workers.add(w);//workers是一个set集合

65                         int s = workers.size();

66                         if (s > largestPoolSize)//largestPoolSize默认为0,作用是记录set集合中的线程数量

67                             largestPoolSize = s;

68                         workerAdded = true;//改变该值,为了启动线程,且返回一个addWorker执行成功的状态

69                     }

70                 } finally {

71                     mainLock.unlock();//释放锁

72                 }

73                 if (workerAdded) {

74                     t.start();

75                     workerStarted = true;

76                 }

77             }

78         } finally {

79             if (! workerStarted)

80                 addWorkerFailed(w);

81         }

82         return workerStarted;

83     }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值