线程池 allowCoreThreadTimeOut 小知识

关于线程池:allowCoreThreadTimeOut(true) 的小知识点

1.背景

   检查别人程序发现堆内存2G,但是常驻内存res到3.2G了,经过一系列操作发现线程特别多(1000+), 当然有重复创建线程池的问题。除此之外,由于是数据域应用,为了加速查询,会定时把数据库数据load到缓存,还不部分是应付也个页面N次(20+)查询,希望能支持稍微高一点的并发响应。所以连接池各方面设置比较大。(线程会持续吃RES内存,不释放,默认1M)

2.操作

	期望线程数减少,定时任务用了线程线程之后,能回收掉等等操作。allowCoreThreadTimeOut 支持回收核心线程,合适定时任务这种回收、其他操作就不介绍了,这里仅回顾下它的回收过程。

3.基本介绍

	代码是:
ThreadPoolExecutor#allowCoreThreadTimeOut(true)
	进去是:
 public void allowCoreThreadTimeOut(boolean value) {
     
        if (value && keepAliveTime <= 0)
            throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
        if (value != allowCoreThreadTimeOut) {
     
            allowCoreThreadTimeOut = value;
            if (value)
                // 中断空闲线程,第一次设置调用
                // workers 还是空的,不太明白作用
                // 因为这个方法是独立,猜测场景是
                // 某任务过程条件下,手动调用该方法一次
                // 比如shutDown 就是一种条件
                interruptIdleWorkers();
        }
    }
   前面都是声明一些东西,还是找到runWorker 执行的地方:
 final void runWorker(Worker w) {
     
 		// 一顿操作略
 		// 这里task 获取不到就会跳出循环 @A
 	  while (task != null || (task = getTask()) != null) {
     
 	  }
 	  // .. 最后会让线程退出
 	  finally {
     
            processWorkerExit(w, completedAbruptly);
        }
 	  // 操作略
 	  
 }

processWorkerExit 代码:

      try {
     
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
     
            mainLock.unlock();
        }

从新回去看@A 里面的getTask

 private Runnable getTask() {
     
        boolean timedOut = false; 
        for (;;) {
     
            // 一顿操作 省略
            try {
     
                   // 这里就用到 allowCoreThreadTimeOut 来判断这个值
                   boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
                   
                 // 这个值又会作为 poll 还是 take 的条件  
                 // 由于timed=true,所以我们会用poll
                 // 然后超过 keepAliveTime 没有活动线程,那么就会返回空,从而触发@A 部分跳出循环,回收线程
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
     
                timedOut = false;
            }
        }
    }

那么如果 allowCoreThreadTimeOut=false
没超过核心线程数的情况下、或者异常、中断等情况下
就会进入 workQueue.take() 阻塞等待,那么刚才执行已经执行过任务的那部分核心线程就不会被回收了。

小结:

  1.虽然线程池用了很久,从1.6 到1.8 都看了下源码,但是还是有些场景和知识点遗忘的地方,仅作为学习记录,加深下印象。
  2.关于线程池的应用很多,从低延迟高并发触发,从IO/CPU 出发,从定时任务量、机器资源排队情况等,需要结合经验、压测,以及合理的业务、线程池拆分找到合适的选择

你可能感兴趣的:(JAVA,基础,java)