jdk线程池线程复用原理

今天去面试,面试官问到一个关于线程池的问题,就是java.util.concurrent包线程池有哪些,我大喜,这不容易吗,我甚至不用思考就回答出来了,面试官也点点头,以为就这样过去了? 面试官突然又问,线程池是怎么实现线程复用的? 好吧,我一下子蒙圈了,乱说了一通,很显然没有让面试官满意,于是就接着问下个问题了……

回来路上在想,平时有用线程池,但是这个问题真的是没有仔细思考过,也许是因为站在大神的肩膀上,也许是因为自己的惰性,总之,我决定回来看看源码,弄清楚其中的原理。

其实很简单,线程池无非就是初始化好线程,避免每次都去创建和销毁线程造成资源的浪费,核心部分包括核心线程数、最大线程数、工作线程以及队列。

我们看ThreadPoolExecutor这个类,下面截了部分代码(不全)

    private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */
        private static final long serialVersionUID = 6138294804551838833L;

        /** Thread this worker is running in.  Null if factory fails. */
        final Thread thread;
        /** Initial task to run.  Possibly null. */
        Runnable firstTask;
        /** Per-thread task counter */
        volatile long completedTasks;

        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
            runWorker(this);
        }
  ……

里面有一个内部类Worker,这个就是工作线程,我们提交的任务都由它来执行。
再看ThreadPoolExecutor的addWorker方法

   boolean workerStarted = false;
   boolean workerAdded = false;
   Worker w = null;
   try {
       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();
                   workers.add(w);
                   int s = workers.size();
                   if (s > largestPoolSize)
                       largestPoolSize = s;
                   workerAdded = true;
               }
           } finally {
               mainLock.unlock();
           }
           if (workerAdded) {
               t.start();
               workerStarted = true;
           }
       }
   } finally {
       if (! workerStarted)
           addWorkerFailed(w);
   }
   return workerStarted;

我们看到有一句t.start();这里就是创建一个新的线程,然后会调用Worker中的run方法,执行runWorker

  final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {

再看getTask()方法

 Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();

重点就在这行代码,从队列取任务用到了两个方法,poll和take,前者是非阻塞的take是阻塞性的
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
很明显,如果工作线程数大于核心线程数,则用的是非阻塞的poll,所以线程会执行完run方法,最后被销毁,如果工作线程数小于核心线程数则会阻塞,不停的从队列里面去取任务执行,run方法不会结束,所以线程可以复用,直到线程池被销毁。

补充一下,就是关于corePoolSize、maximumPoolSize和workQueue之间关系是怎样的,看下面这段代码:ThreadPoolExecutor.execute方法

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

workQueue.offer(command)为入队,所以我的理解是如果当大于核心线程数并且大于最大线程数时候才需要往workQueue里面添加任务,等待空闲线程执行任务。就是说,刚刚开始workQueue是空的,后面满足条件才往队列里面塞,不知道是否理解正确-_-

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值