亲 , ThreadPoolExecutor : KeepAliveTime了解一下~

Posted JAVA翻译官

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了亲 , ThreadPoolExecutor : KeepAliveTime了解一下~相关的知识,希望对你有一定的参考价值。

先来几个问题:

  1. 如果你来设计这个超时,会怎么设计?

  2. > corePoolSize的线程要不要去执行queue里的task ?

来看看ThreadPoolExecutor 怎么做的?

现在有一个ThreadPoolExecutor,有以下属性:

1corePoolSize : 1 //核心线程数 1 
2maximumPoolSize : 2  // 最大线程数 2 
3queueSize : 1  // 队列容量 1
4keepAliveTime : 5s //存活时间 ,5s
5allowCorePoolTimeOut: false //核心线程不超时

有三个task ,每个task执行不同的时间:

1T1 : 20s // task 1 执行 20s
2T2 : 10s // task 2 执行 10s
3T3 : 5s  // task 3 执行 5s

有以下这个,指定休眠时间的任务:

1    @Override
2    public void run(
{
3        String name = new StringBuilder(Thread.currentThread().getName()).append("-").append(Thread.currentThread().getId()).toString();
4        System.out.println(name + " : start , time:"+time);
5        try {
6            TimeUnit.SECONDS.sleep(time);
7        } catch (InterruptedException e) {}
8        System.out.println(name + " : end , time:"+time);
9    }

得到如下结果:

1pool-1-thread-1-11 : start , time:20
2pool-1-thread-2-12 : start , time:5
3pool-1-thread-2-12 : end , time:5
4pool-1-thread-2-12 : start , time:10
5pool-1-thread-2-12 : end , time:10
6pool-1-thread-1-11 : end , time:20

从结果中看,thread-2 是非core线程,执行了 5s,10s这两个任务。就是说非core线程,会去执行队列任务,直到把队列任务处理完。

那么超时的流程是怎样的 ? 
下面以thread-2来分析。

runWorker()

 1final void runWorker(Worker w) {
2    .......
3    try {
4        while (task != null || (task = getTask()) != null) { // 1
5            .....
6            task.run(); // 2
7            .....
8        }
9        .......
10    } finally {
11        processWorkerExit(w, completedAbruptly); // 3
12    }
13}
14private void processWorkerExit(Worker w, boolean completedAbruptly) {
15    ....
16    workers.remove(w); // 4
17    .....
18}
  1. task != null || getTask() != null
    第一次,worker执行完task后,下次循环getTask()去队列中拿 task.

  2. 拿到了task,执行task

  3. 没有拿到task , task == null,(此时队列中没有了任务) . 执行清除线程

  4. 将worker从线程池中remove掉。

getTask()

 1private Runnable getTask({
2    ......
3    for (;;) {         // 1     
4        .....
5        try {
6            Runnable r = timed ?   // 2
7                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :   //3
8                workQueue.take();   // 4
9            if (r != null
10                return r;
11            timedOut = true;        // 5
12        } catch (InterruptedException retry) {
13            timedOut = false;       // 6
14        }
15    }
16}
  1. 线程无限循环去取task

  2. 是否有超时限制。取不同的策略

  3. 有超时,poll的逻辑 (非core线程)

    1. 有task , 返回 task,--> 接runWorker()的第二步。执行task

    2. 没有task , 返回 null. --> 接runWorker()的第三步。清除线程

    3. queue中有task,则直接取出task,并返回。不理会keepAliveTime.

    4. queue中没有task , 则线程阻塞等待keepAliveTime的时间 : LockSupport.park(keepAliveTime)

    5. 阻塞等待时间结束后,再去取一次task,

  4. 不限制超时 (core线程)

    1. queue中有task,返回task

    2. queue中没有task,则线程阻塞 :LockSupport.park(0L) 。永久阻塞,直到被唤醒。

workerQueue.offer(task)

当corePoolSize已经创建满了之后。再有新的task进来时,不是直接交给线程执行的。
而是放到队列中,然后唤醒一个线程,去执行task 。

问题解答:

  1. ThreadPoolExecutor设计的keepAliveTime是通过阻塞线程的方法 。等待keepAliveTime的时长后,还没有task,则将线程清除。

  2. 非core线程,会去队列中拿task去执行。直到队列中task被执行完。

再留下一个坑:
当有多个core线程被阻塞时,唤醒操作时?

  1. 唤醒全部线程吗 ?为什么 ?

  2. 不是的话,唤醒的是哪个线程呢 ?


以上是关于亲 , ThreadPoolExecutor : KeepAliveTime了解一下~的主要内容,如果未能解决你的问题,请参考以下文章

将 InheritableThreadLocal 与 ThreadPoolExecutor - 或 - 不重用线程的 ThreadPoolExecutor 一起使用

ThreadPoolExecutor的参数介绍

ThreadPoolExecutor的一种扩展办法

JavaFX 多线程之 ThreadPoolExecutor 线程池

[转发]对ThreadPoolExecutor初识

使用ThreadPoolExecutor进行多线程编程