资讯专栏INFORMATION COLUMN

原理剖析(第 003 篇)ThreadPoolExecutor工作原理分析

CatalpaFlat / 1466人阅读

摘要:原理剖析第篇工作原理分析一大致介绍相信大家都用过线程池,对该类应该一点都不陌生了我们之所以要用到线程池,线程池主要用来解决线程生命周期开销问题和资源不足问题我们通过对多个任务重用线程以及控制线程池的数目可以有效防止资源不足的情况本章节就着

原理剖析(第 003 篇)ThreadPoolExecutor工作原理分析

-

一、大致介绍

</>复制代码

  1. 1、相信大家都用过线程池,对该类ThreadPoolExecutor应该一点都不陌生了;
  2. 2、我们之所以要用到线程池,线程池主要用来解决线程生命周期开销问题和资源不足问题;
  3. 3、我们通过对多个任务重用线程以及控制线程池的数目可以有效防止资源不足的情况;
  4. 4、本章节就着重和大家分享分析一下JDK8的ThreadPoolExecutor核心类,看看线程池是如何工作的;
二、基本字段方法介绍 2.1 构造器

</>复制代码

  1. 1、四个构造器:
  2. // 构造器一
  3. public ThreadPoolExecutor(int corePoolSize,
  4. int maximumPoolSize,
  5. long keepAliveTime,
  6. TimeUnit unit,
  7. BlockingQueue workQueue) {
  8. this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
  9. Executors.defaultThreadFactory(), defaultHandler);
  10. }
  11. // 构造器二
  12. public ThreadPoolExecutor(int corePoolSize,
  13. int maximumPoolSize,
  14. long keepAliveTime,
  15. TimeUnit unit,
  16. BlockingQueue workQueue,
  17. ThreadFactory threadFactory) {
  18. this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
  19. threadFactory, defaultHandler);
  20. }
  21. // 构造器三
  22. public ThreadPoolExecutor(int corePoolSize,
  23. int maximumPoolSize,
  24. long keepAliveTime,
  25. TimeUnit unit,
  26. BlockingQueue workQueue,
  27. RejectedExecutionHandler handler) {
  28. this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
  29. Executors.defaultThreadFactory(), handler);
  30. }
  31. // 构造器四
  32. public ThreadPoolExecutor(int corePoolSize,
  33. int maximumPoolSize,
  34. long keepAliveTime,
  35. TimeUnit unit,
  36. BlockingQueue workQueue,
  37. ThreadFactory threadFactory,
  38. RejectedExecutionHandler handler) {
  39. if (corePoolSize < 0 ||
  40. maximumPoolSize <= 0 ||
  41. maximumPoolSize < corePoolSize ||
  42. keepAliveTime < 0)
  43. throw new IllegalArgumentException();
  44. if (workQueue == null || threadFactory == null || handler == null)
  45. throw new NullPointerException();
  46. this.corePoolSize = corePoolSize;
  47. this.maximumPoolSize = maximumPoolSize;
  48. this.workQueue = workQueue;
  49. this.keepAliveTime = unit.toNanos(keepAliveTime);
  50. this.threadFactory = threadFactory;
  51. this.handler = handler;
  52. }
  53. 2、通过仔细查看构造器代码,发现最终都是调用构造器四,紧接着赋值了一堆的字段,接下来我们先看看这些字段是什么含义;
2.2 成员变量字段

</>复制代码

  1. 1、corePoolSize:核心运行的线程池数量大小,当线程数量超过该值时,就需要将超过该数量值的线程放到等待队列中;
  2. 2、maximumPoolSize:线程池最大能容纳的线程数(该数量已经包含了corePoolSize数量),当线程数量超过该值时,则会拒绝执行处理策略;
  3. 3、workQueue:等待队列,当达到corePoolSize的时候,就将新加入的线程追加到workQueue该等待队列中;
  4. 当然BlockingQueue类也是一个抽象类,也有很多子类来实现不同的队列等待;
  5. 一般来说,阻塞队列有一下几种,ArrayBlockingQueue;LinkedBlockingQueue/SynchronousQueue/ArrayBlockingQueue/
  6. PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。
  7. 4、keepAliveTime:表示线程没有任务执行时最多保持多久存活时间,默认情况下当线程数量大于corePoolSize后keepAliveTime才会起作用
  8. 并生效,一旦线程池的数量小于corePoolSize后keepAliveTime又不起作用了;
  9. 但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,
  10. keepAliveTime参数也会起作用,直到线程池中的线程数为0;
  11. 5、threadFactory:新创建线程出生的地方;
  12. 6、handler:拒绝执行处理抽象类,就是说当线程池在一些场景中,不能处理新加入的线程任务时,会通过该对象处理拒绝策略;
  13. 该对象RejectedExecutionHandler有四个实现类,即四种策略,让我们有选择性的在什么场景下该怎么使用拒绝策略;
  14. 策略一( CallerRunsPolicy ):只要线程池没关闭,就直接用调用者所在线程来运行任务;
  15. 策略二( AbortPolicy ):默认策略,直接抛出RejectedExecutionException异常;
  16. 策略三( DiscardPolicy ):执行空操作,什么也不干,拒绝任务后也不做任何回应;
  17. 策略四( DiscardOldestPolicy ):将队列中存活最久的那个未执行的任务抛弃掉,然后将当前新的线程放进去;
  18. 7、largestPoolSize:变量记录了线程池在整个生命周期中曾经出现的最大线程个数;
  19. 8、allowCoreThreadTimeOut:当为true时,和弦线程也有超时退出的概念一说;
2.3 成员方法

</>复制代码

  1. 1、AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
  2. // 原子变量值,是一个复核类型的成员变量,是一个原子整数,借助高低位包装了两个概念:
  3. 2int COUNT_BITS = Integer.SIZE - 3;
  4. // 偏移位数,常量值29,之所以偏移29,目的是将32位的原子变量值ctl的高3位设置为线程池的状态,低29位作为线程池大小数量值;
  5. 3int CAPACITY = (1 << COUNT_BITS) - 1;
  6. // 线程池的最大容量值;
  7. 4、线程池的状态,原子变量值ctl的高三位:
  8. int RUNNING = -1 << COUNT_BITS; // 接受新任务,并处理队列任务
  9. int SHUTDOWN = 0 << COUNT_BITS; // 不接受新任务,但会处理队列任务
  10. int STOP = 1 << COUNT_BITS; // 不接受新任务,不会处理队列任务,而且会中断正在处理过程中的任务
  11. int TIDYING = 2 << COUNT_BITS; // 所有的任务已结束,workerCount为0,线程过渡到TIDYING状态,将会执行terminated()钩子方法
  12. int TERMINATED = 3 << COUNT_BITS; // terminated()方法已经完成
  13. 5、HashSet workers = new HashSet();
  14. // 存放工作线程的线程池;
2.4 成员方法

</>复制代码

  1. 1public void execute(Runnable command)
  2. // 提交任务,添加Runnable对象到线程池,由线程池调度执行
  3. 2private static int workerCountOf(int c) { return c & CAPACITY; }
  4. // c & 高3位为0,低29位为1的CAPACITY,用于获取低29位的线程数量
  5. 3private boolean addWorker(Runnable firstTask, boolean core)
  6. // 添加worker工作线程,根据边界值来决定是否创建新的线程
  7. 4private static boolean isRunning(int c)
  8. // c通常一般为ctl,ctl值小于0,则处于可以接受新任务状态
  9. 5final void reject(Runnable command)
  10. // 拒绝执行任务方法,当线程池在一些场景中,不能处理新加入的线程时,会通过该对象处理拒绝策略;
  11. 6final void runWorker(Worker w)
  12. // 该方法被Worker工作线程的run方法调用,真正核心处理Runable任务的方法
  13. 7private static int runStateOf(int c) { return c & ~CAPACITY; }
  14. // c & 高3位为1,低29位为0的~CAPACITY,用于获取高3位保存的线程池状态
  15. 8public void shutdown()
  16. // 不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
  17. 9public List shutdownNow()
  18. // 立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
  19. 10private void processWorkerExit(Worker w, boolean completedAbruptly)
  20. // worker线程退出
三、源码分析 3.1、execute

</>复制代码

  1. 1、execute源码:
  2. /**
  3. * Executes the given task sometime in the future. The task
  4. * may execute in a new thread or in an existing pooled thread.
  5. *
  6. * If the task cannot be submitted for execution, either because this
  7. * executor has been shutdown or because its capacity has been reached,
  8. * the task is handled by the current {@code RejectedExecutionHandler}.
  9. *
  10. * @param command the task to execute
  11. * @throws RejectedExecutionException at discretion of
  12. * {@code RejectedExecutionHandler}, if the task
  13. * cannot be accepted for execution
  14. * @throws NullPointerException if {@code command} is null
  15. */
  16. public void execute(Runnable command) {
  17. if (command == null)
  18. throw new NullPointerException();
  19. /*
  20. * Proceed in 3 steps:
  21. *
  22. * 1. If fewer than corePoolSize threads are running, try to
  23. * start a new thread with the given command as its first
  24. * task. The call to addWorker atomically checks runState and
  25. * workerCount, and so prevents false alarms that would add
  26. * threads when it shouldn"t, by returning false.
  27. *
  28. * 2. If a task can be successfully queued, then we still need
  29. * to double-check whether we should have added a thread
  30. * (because existing ones died since last checking) or that
  31. * the pool shut down since entry into this method. So we
  32. * recheck state and if necessary roll back the enqueuing if
  33. * stopped, or start a new thread if there are none.
  34. *
  35. * 3. If we cannot queue task, then we try to add a new
  36. * thread. If it fails, we know we are shut down or saturated
  37. * and so reject the task.
  38. */
  39. int c = ctl.get(); // 获取原子计数值最新值
  40. if (workerCountOf(c) < corePoolSize) { // 判断当前线程池数量是否小于核心线程数量
  41. if (addWorker(command, true)) // 尝试添加command任务到核心线程
  42. return;
  43. c = ctl.get(); // 重新获取当前线程池状态值,为后面的检查做准备。
  44. }
  45. // 执行到此,说明核心线程任务数量已满,新添加的线程入等待队列,这个熟练是大于corePoolSize且小于maximumPoolSize
  46. if (isRunning(c) && workQueue.offer(command)) { // 如果线程池处于可接受任务状态,尝试添加到等待队列
  47. int recheck = ctl.get(); // 双重校验
  48. if (! isRunning(recheck) && remove(command)) // 如果线程池突然不可接受任务,则尝试移除该command任务
  49. reject(command); // 不可接受任务且成功从等待队列移除任务,则执行拒绝策略操作,通过策略告诉调用方任务入队情况
  50. else if (workerCountOf(recheck) == 0) // 如果此刻线程数量为0的话将没有Worker执行新的task,所以增加一个Worker
  51. addWorker(null, false); // 添加一个Worker
  52. }
  53. // 执行到此,说明添加任务等待队列已满,所以尝试添加一个Worker
  54. else if (!addWorker(command, false)) // 如果添加失败的话,那么拒绝此线程任务添加
  55. reject(command); // 拒绝此线程任务添加
  56. }
  57. 2、小结:
  58. • 如果线程池中的线程数量 < corePoolSize,就创建新的线程来执行新添加的任务;
  59. • 如果线程池中的线程数量 >= corePoolSize,但队列workQueue未满,则将新添加的任务放到workQueue中;
  60. • 如果线程池中的线程数量 >= corePoolSize,且队列workQueue已满,但线程池中的线程数量 < maximumPoolSize,则会创建新的线程来处理被添加的任务;
  61. • 如果线程池中的线程数量 = maximumPoolSize,就用RejectedExecutionHandler来执行拒绝策略;
3.2、addWorker

</>复制代码

  1. 1、addWorker源码:
  2. /**
  3. * Checks if a new worker can be added with respect to current
  4. * pool state and the given bound (either core or maximum). If so,
  5. * the worker count is adjusted accordingly, and, if possible, a
  6. * new worker is created and started, running firstTask as its
  7. * first task. This method returns false if the pool is stopped or
  8. * eligible to shut down. It also returns false if the thread
  9. * factory fails to create a thread when asked. If the thread
  10. * creation fails, either due to the thread factory returning
  11. * null, or due to an exception (typically OutOfMemoryError in
  12. * Thread.start()), we roll back cleanly.
  13. *
  14. * @param firstTask the task the new thread should run first (or
  15. * null if none). Workers are created with an initial first task
  16. * (in method execute()) to bypass queuing when there are fewer
  17. * than corePoolSize threads (in which case we always start one),
  18. * or when the queue is full (in which case we must bypass queue).
  19. * Initially idle threads are usually created via
  20. * prestartCoreThread or to replace other dying workers.
  21. *
  22. * @param core if true use corePoolSize as bound, else
  23. * maximumPoolSize. (A boolean indicator is used here rather than a
  24. * value to ensure reads of fresh values after checking other pool
  25. * state).
  26. * @return true if successful
  27. */
  28. private boolean addWorker(Runnable firstTask, boolean core) {
  29. retry: // 外层循环,负责判断线程池状态,处理线程池状态变量加1操作
  30. for (;;) {
  31. int c = ctl.get();
  32. int rs = runStateOf(c); // 读取状态值
  33. // Check if queue empty only if necessary.
  34. // 满足下面两大条件的,说明线程池不能接受任务了,直接返回false处理
  35. // 主要目的就是想说,只有线程池的状态为 RUNNING 状态时,线程池才会接收新的任务,增加新的Worker工作线程
  36. if (rs >= SHUTDOWN && // 线程池的状态已经至少已经处于不能接收任务的状态了,目的是检查线程池是否处于关闭状态
  37. ! (rs == SHUTDOWN &&
  38. firstTask == null &&
  39. ! workQueue.isEmpty()))
  40. return false;
  41. // 内层循环,负责worker数量加1操作
  42. for (;;) {
  43. int wc = workerCountOf(c); // 获取当前worker线程数量
  44. if (wc >= CAPACITY || // 如果线程池数量达到最大上限值CAPACITY
  45. // core为true时判断是否大于corePoolSize核心线程数量
  46. // core为false时判断是否大于maximumPoolSize最大设置的线程数量
  47. wc >= (core ? corePoolSize : maximumPoolSize))
  48. return false;
  49. // 调用CAS原子操作,目的是worker线程数量加1
  50. if (compareAndIncrementWorkerCount(c)) //
  51. break retry;
  52. c = ctl.get(); // Re-read ctl // CAS原子操作失败的话,则再次读取ctl值
  53. if (runStateOf(c) != rs) // 如果刚刚读取的c状态不等于先前读取的rs状态,则继续外层循环判断
  54. continue retry;
  55. // else CAS failed due to workerCount change; retry inner loop
  56. // 之所以会CAS操作失败,主要是由于多线程并发操作,导致workerCount工作线程数量改变而导致的,因此继续内层循环尝试操作
  57. }
  58. }
  59. boolean workerStarted = false;
  60. boolean workerAdded = false;
  61. Worker w = null;
  62. try {
  63. // 创建一个Worker工作线程对象,将任务firstTask,新创建的线程thread都封装到了Worker对象里面
  64. w = new Worker(firstTask);
  65. final Thread t = w.thread;
  66. if (t != null) {
  67. // 由于对工作线程集合workers的添加或者删除,涉及到线程安全问题,所以才加上锁且该锁为非公平锁
  68. final ReentrantLock mainLock = this.mainLock;
  69. mainLock.lock();
  70. try {
  71. // Recheck while holding lock.
  72. // Back out on ThreadFactory failure or if
  73. // shut down before lock acquired.
  74. // 获取锁成功后,执行临界区代码,首先检查获取当前线程池的状态rs
  75. int rs = runStateOf(ctl.get());
  76. // 当线程池处于可接收任务状态
  77. // 或者是不可接收任务状态,但是有可能该任务等待队列中的任务
  78. // 满足这两种条件时,都可以添加新的工作线程
  79. if (rs < SHUTDOWN ||
  80. (rs == SHUTDOWN && firstTask == null)) {
  81. if (t.isAlive()) // precheck that t is startable
  82. throw new IllegalThreadStateException();
  83. workers.add(w); // 添加新的工作线程到工作线程集合workers,workers是set集合
  84. int s = workers.size();
  85. if (s > largestPoolSize) // 变量记录了线程池在整个生命周期中曾经出现的最大线程个数
  86. largestPoolSize = s;
  87. workerAdded = true;
  88. }
  89. } finally {
  90. mainLock.unlock();
  91. }
  92. if (workerAdded) { // 往workers工作线程集合中添加成功后,则立马调用线程start方法启动起来
  93. t.start();
  94. workerStarted = true;
  95. }
  96. }
  97. } finally {
  98. if (! workerStarted) // 如果启动线程失败的话,还得将刚刚添加成功的线程共集合中移除并且做线程数量做减1操作
  99. addWorkerFailed(w);
  100. }
  101. return workerStarted;
  102. }
  103. 2、小结:
  104. • 该方法是任务提交的一个核心方法,主要完成状态的检查,工作线程的创建并添加到线程集合切最后顺利的话将创建的线程启动;
  105. • addWorker(command, true):当线程数小于corePoolSize时,添加一个需要处理的任务command进线程集合,如果workers数量超过corePoolSize时,则返回false不需要添加工作线程;
  106. • addWorker(command, false):当等待队列已满时,将新来的任务command添加到workers线程集合中去,若线程集合大小超过maximumPoolSize时,则返回false不需要添加工作线程;
  107. • addWorker(null, false):放一个空的任务进线程集合,当这个空任务的线程执行时,会从等待任务队列中通过getTask获取任务再执行,创建新线程且没有任务分配,当执行时才去取任务;
  108. • addWorker(null, true):创建空任务的工作线程到workers集合中去,在setCorePoolSize方法调用时目的是初始化核心工作线程实例;
3.3、runWorker

</>复制代码

  1. 1、runWorker源码:
  2. /**
  3. * Main worker run loop. Repeatedly gets tasks from queue and
  4. * executes them, while coping with a number of issues:
  5. *
  6. * 1. We may start out with an initial task, in which case we
  7. * don"t need to get the first one. Otherwise, as long as pool is
  8. * running, we get tasks from getTask. If it returns null then the
  9. * worker exits due to changed pool state or configuration
  10. * parameters. Other exits result from exception throws in
  11. * external code, in which case completedAbruptly holds, which
  12. * usually leads processWorkerExit to replace this thread.
  13. *
  14. * 2. Before running any task, the lock is acquired to prevent
  15. * other pool interrupts while the task is executing, and then we
  16. * ensure that unless pool is stopping, this thread does not have
  17. * its interrupt set.
  18. *
  19. * 3. Each task run is preceded by a call to beforeExecute, which
  20. * might throw an exception, in which case we cause thread to die
  21. * (breaking loop with completedAbruptly true) without processing
  22. * the task.
  23. *
  24. * 4. Assuming beforeExecute completes normally, we run the task,
  25. * gathering any of its thrown exceptions to send to afterExecute.
  26. * We separately handle RuntimeException, Error (both of which the
  27. * specs guarantee that we trap) and arbitrary Throwables.
  28. * Because we cannot rethrow Throwables within Runnable.run, we
  29. * wrap them within Errors on the way out (to the thread"s
  30. * UncaughtExceptionHandler). Any thrown exception also
  31. * conservatively causes thread to die.
  32. *
  33. * 5. After task.run completes, we call afterExecute, which may
  34. * also throw an exception, which will also cause thread to
  35. * die. According to JLS Sec 14.20, this exception is the one that
  36. * will be in effect even if task.run throws.
  37. *
  38. * The net effect of the exception mechanics is that afterExecute
  39. * and the thread"s UncaughtExceptionHandler have as accurate
  40. * information as we can provide about any problems encountered by
  41. * user code.
  42. *
  43. * @param w the worker
  44. */
  45. final void runWorker(Worker w) {
  46. Thread wt = Thread.currentThread();
  47. Runnable task = w.firstTask;
  48. w.firstTask = null;
  49. w.unlock(); // allow interrupts 允许中断
  50. boolean completedAbruptly = true;
  51. try {
  52. // 不断从等待队列blockingQueue中获取任务
  53. // 之前addWorker(null, false)这样的线程执行时,会通过getTask中再次获取任务并执行
  54. while (task != null || (task = getTask()) != null) {
  55. w.lock(); // 上锁,并不是防止并发执行任务,而是为了防止shutdown()被调用时不终止正在运行的worker线程
  56. // If pool is stopping, ensure thread is interrupted;
  57. // if not, ensure thread is not interrupted. This
  58. // requires a recheck in second case to deal with
  59. // shutdownNow race while clearing interrupt
  60. if ((runStateAtLeast(ctl.get(), STOP) ||
  61. (Thread.interrupted() &&
  62. runStateAtLeast(ctl.get(), STOP))) &&
  63. !wt.isInterrupted())
  64. wt.interrupt();
  65. try {
  66. // task.run()执行前,由子类实现
  67. beforeExecute(wt, task);
  68. Throwable thrown = null;
  69. try {
  70. task.run(); // 执行线程Runable的run方法
  71. } catch (RuntimeException x) {
  72. thrown = x; throw x;
  73. } catch (Error x) {
  74. thrown = x; throw x;
  75. } catch (Throwable x) {
  76. thrown = x; throw new Error(x);
  77. } finally {
  78. // task.run()执行后,由子类实现
  79. afterExecute(task, thrown);
  80. }
  81. } finally {
  82. task = null;
  83. w.completedTasks++;
  84. w.unlock();
  85. }
  86. }
  87. completedAbruptly = false;
  88. } finally {
  89. processWorkerExit(w, completedAbruptly);
  90. }
  91. }
  92. 2、小结:
  93. addWorker通过调用t.start()启动了线程,线程池的真正核心执行任务的地方就在此runWorker中;
  94. • 不断的执行我们提交任务的run方法,可能是刚刚提交的任务,可能是队列中等待的队列,原因在于Worker工作线程类继承了AQS类;
  95. • Worker重写了AQS的tryAcquire方法,不管先来后到,一种非公平的竞争机制,通过CAS获取锁,获取到了就执行代码块,没获取到的话则添加到CLH队列中通过利用LockSuporrt的park/unpark阻塞任务等待;
  96. addWorker通过调用t.start()启动了线程,线程池的真正核心执行任务的地方就在此runWorker中;
3.processWorkerExit

</>复制代码

  1. 1、processWorkerExit源码:
  2. /**
  3. * Performs cleanup and bookkeeping for a dying worker. Called
  4. * only from worker threads. Unless completedAbruptly is set,
  5. * assumes that workerCount has already been adjusted to account
  6. * for exit. This method removes thread from worker set, and
  7. * possibly terminates the pool or replaces the worker if either
  8. * it exited due to user task exception or if fewer than
  9. * corePoolSize workers are running or queue is non-empty but
  10. * there are no workers.
  11. *
  12. * @param w the worker
  13. * @param completedAbruptly if the worker died due to user exception
  14. */
  15. private void processWorkerExit(Worker w, boolean completedAbruptly) {
  16. // 如果突然中止,说明runWorker中遇到什么异常了,那么正在工作的线程自然就需要减1操作了
  17. if (completedAbruptly) // If abrupt, then workerCount wasn"t adjusted
  18. decrementWorkerCount();
  19. final ReentrantLock mainLock = this.mainLock;
  20. // 执行到此,说明runWorker正常执行完了,需要正常退出工作线程,上锁正常操作移除线程
  21. mainLock.lock();
  22. try {
  23. completedTaskCount += w.completedTasks; // 增加线程池完成任务数
  24. workers.remove(w); // 从workers线程集合中移除已经工作完的线程
  25. } finally {
  26. mainLock.unlock();
  27. }
  28. // 在对线程池有负效益的操作时,都需要“尝试终止”线程池,主要是判断线程池是否满足终止的状态;
  29. // 如果状态满足,但还有线程池还有线程,尝试对其发出中断响应,使其能进入退出流程;
  30. // 没有线程了,更新状态为tidying->terminated;
  31. tryTerminate();
  32. int c = ctl.get();
  33. // 如果状态是running、shutdown,即tryTerminate()没有成功终止线程池,尝试再添加一个worker
  34. if (runStateLessThan(c, STOP)) {
  35. // 不是突然完成的,即没有task任务可以获取而完成的,计算min,并根据当前worker数量判断是否需要addWorker()
  36. if (!completedAbruptly) {
  37. int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
  38. // 如果min为0,且workQueue不为空,至少保持一个线程
  39. if (min == 0 && ! workQueue.isEmpty())
  40. min = 1;
  41. // 如果线程数量大于最少数量,直接返回,否则下面至少要addWorker一个
  42. if (workerCountOf(c) >= min)
  43. return; // replacement not needed
  44. }
  45. // 只要worker是completedAbruptly突然终止的,或者线程数量小于要维护的数量,就新添一个worker线程,即使是shutdown状态
  46. addWorker(null, false);
  47. }
  48. }
  49. 2、小结:
  50. • 异常中止情况worker数量减1,正常情况就上锁从workers中移除;
  51. • tryTerminate():在对线程池有负效益的操作时,都需要“尝试终止”线程池;
  52. • 是否需要增加worker线程,如果线程池还没有完全终止,仍需要保持一定数量的线程;
四、一些建议 4.1、合理配置线程池的大小(仅供参考)

</>复制代码

  1. 1、如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 NCPU+1;
  2. 2、如果是IO密集型任务,参考值可以设置为2*NCPU;
4.2、JDK帮助文档建议

</>复制代码

  1. “强烈建议程序员使用较为方便的Executors工厂方法:
五、下载地址

https://gitee.com/ylimhhmily/SpringCloudTutorial.git

SpringCloudTutorial交流QQ群: 235322432

SpringCloudTutorial交流微信群: 微信沟通群二维码图片链接

欢迎关注,您的肯定是对我最大的支持!!!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68764.html

相关文章

  • 原理剖析 004 )CAS工作原理分析

    摘要:原理剖析第篇工作原理分析一大致介绍关于多线程竞争锁方面,大家都知道有个和,也正是这两个东西才引申出了大量的线程安全类,锁类等功能而随着现在的硬件厂商越来越高级,在硬件层面提供大量并发原语给我们层面的开发带来了莫大的利好本章节就和大家分享分 原理剖析(第 004 篇)CAS工作原理分析 - 一、大致介绍 1、关于多线程竞争锁方面,大家都知道有个CAS和AQS,也正是这两个东西才引申出了大...

    leanote 评论0 收藏0
  • 高并发

    摘要:表示的是两个,当其中任意一个计算完并发编程之是线程安全并且高效的,在并发编程中经常可见它的使用,在开始分析它的高并发实现机制前,先讲讲废话,看看它是如何被引入的。电商秒杀和抢购,是两个比较典型的互联网高并发场景。 干货:深度剖析分布式搜索引擎设计 分布式,高可用,和机器学习一样,最近几年被提及得最多的名词,听名字多牛逼,来,我们一步一步来击破前两个名词,今天我们首先来说说分布式。 探究...

    supernavy 评论0 收藏0
  • 高并发

    摘要:表示的是两个,当其中任意一个计算完并发编程之是线程安全并且高效的,在并发编程中经常可见它的使用,在开始分析它的高并发实现机制前,先讲讲废话,看看它是如何被引入的。电商秒杀和抢购,是两个比较典型的互联网高并发场景。 干货:深度剖析分布式搜索引擎设计 分布式,高可用,和机器学习一样,最近几年被提及得最多的名词,听名字多牛逼,来,我们一步一步来击破前两个名词,今天我们首先来说说分布式。 探究...

    ddongjian0000 评论0 收藏0
  • 高并发

    摘要:表示的是两个,当其中任意一个计算完并发编程之是线程安全并且高效的,在并发编程中经常可见它的使用,在开始分析它的高并发实现机制前,先讲讲废话,看看它是如何被引入的。电商秒杀和抢购,是两个比较典型的互联网高并发场景。 干货:深度剖析分布式搜索引擎设计 分布式,高可用,和机器学习一样,最近几年被提及得最多的名词,听名字多牛逼,来,我们一步一步来击破前两个名词,今天我们首先来说说分布式。 探究...

    wangdai 评论0 收藏0
  • 原理剖析 011 )Netty之服务端启动工作原理分析(下)

    摘要:原理剖析第篇之服务端启动工作原理分析下一大致介绍由于篇幅过长难以发布,所以本章节接着上一节来的,上一章节为原理剖析第篇之服务端启动工作原理分析上那么本章节就继续分析的服务端启动,分析的源码版本为二三四章节请看上一章节详见原理剖析第篇之 原理剖析(第 011 篇)Netty之服务端启动工作原理分析(下) - 一、大致介绍 1、由于篇幅过长难以发布,所以本章节接着上一节来的,上一章节为【原...

    Tikitoo 评论0 收藏0

发表评论

0条评论

CatalpaFlat

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<