美文网首页
java ThreadPoolExecutor踩坑记

java ThreadPoolExecutor踩坑记

作者: Ronry | 来源:发表于2017-08-22 21:51 被阅读0次

    首先简单介绍下ThreadPoolExecutor的原理,如图:


    image.png

    每当有新任务需要提交到线程池执行的时候,大概的过程如下:

    • step1.调用ThreadPoolExecutor的execute提交线程,首先检查CorePool,如果CorePool内的线程小于CorePoolSize,新创建线程执行任务。
    • step2.如果当前CorePool内的线程大于等于CorePoolSize,那么将任务加入到BlockingQueue。
    • step3.如果不能加入BlockingQueue,在小于MaxPoolSize的情况下创建线程执行任务。
    • step4.如果线程数大于等于MaxPoolSize,那么执行拒绝策略。

    其中1,2,4步骤的机制原来也就知道,只是对于step3原先关注的不多,这次踩到了。本意是想让超出MaxPoolSize的时候,任务能执行在父线程里执行,所以想当然的将BlockingQueue的大小设置为1了。结果出现的现象是,在并发很低的情况下,出现了任务被线程池拒绝的情况。调试了一下午,才发现卡在了step3,源代码如下:

           int c = ctl.get();
            if (workerCountOf(c) < corePoolSize) {
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            } 
           // step 3 workQueue.offer(command))
            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);
    

    关键点就在workQueue.offer(command))这句:如果当前线程数已经大于coreSize了,则会先尝试往对列里放。如果队列已经满了,则直接看能不能再建线程,如果还不能则走拒绝策略。这个时候,其实coreSize的线程可能都是空闲的,他们是在等待workQueue里有新的任务出现。而新的任务(特别是一次性批量提交大于1个的时候),因为BlockingQueue size是1,所以只有1个能提交成功,其他的都被拒绝了。
    想想也是啊,这就是一个生产者消费者模式,线程被创建出来之后,和后续提交的任务之间唯一媒介就是workQueue!!

    更详细的关于ThreadPoolExecutor的机制可以参考:
    http://www.jianshu.com/p/ade771d2c9c0

    相关文章

      网友评论

          本文标题:java ThreadPoolExecutor踩坑记

          本文链接:https://www.haomeiwen.com/subject/vwkrdxtx.html