线程池详解

线程池详解

Posted by bulingfeng on July 2, 2023

简介

线程池其实就是为了减少线程的频繁创建和销毁,从而能够使线程得到充分利用,这样就可以提高系统的性能和运行效率。

常见的线程池创建方式

  • ThreadPoolExecutor
  • 使用Executors来创建各种线程池,比如newFixedThreadPool(int threadNum);

线程池execute运行策略

其实execute和submit执行逻辑都一样,submit底层实现其实也是在execute方法的基础上来进行实现的。

那我们来看下execute的源代码吧java.util.concurrent.ThreadPoolExecutor#execute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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);
    }

其中涉及到work的流程,有个博客写的不错,可以参考一下:

1
https://juejin.cn/post/6866054685044768782

详细解释

  1. 当任务数小于coreNum的时候,创建一个线程来执行任务。
  2. 当任务数量大于coreNum的时候,并且小于队列规定最大任务数量的时候,把任务放到队列里面
  3. 当任务数大于coreNum的时候,并且线程数还没有达到最大线程数的时候,创建最大线程数量来执行任务
  4. 大于最大线程数,队列已满,调用拒绝策略

其实所有的任务都是先进入到任务队列里面,然后再从队列里面取出来,给线程再执行。

Executor、ExecutorService、Executors直接的关系

Executor和ExecutorService是执行器接口;Executors可以看做是一个线程执行器的工具类。