@@ -211,16 +211,16 @@ static class Entry extends WeakReference<ThreadLocal<?>> {
211211
212212** 方式二:通过 ` Executor ` 框架的工具类 ` Executors ` 来创建。**
213213
214- 我们可以创建多种类型的 ` ThreadPoolExecutor ` :
214+ ` Executors ` 工具类提供的创建线程池的方法如下图所示 :
215215
216- - ** ` FixedThreadPool ` ** :该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
217- - ** ` SingleThreadExecutor ` :** 该方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
218- - ** ` CachedThreadPool ` :** 该方法返回一个可根据实际情况调整线程数量的线程池。初始大小为 0。当有新任务提交时,如果当前线程池中没有线程可用,它会创建一个新的线程来处理该任务。如果在一段时间内(默认为 60 秒)没有新任务提交,核心线程会超时并被销毁,从而缩小线程池的大小。
219- - ** ` ScheduledThreadPool ` ** :该方法返回一个用来在给定的延迟后运行任务或者定期执行任务的线程池。
216+ ![ ] ( https://oss.javaguide.cn/github/javaguide/java/concurrent/executors-new-thread-pool-methods.png )
220217
221- 对应 ` Executors ` 工具类中的方法如图所示 :
218+ 可以看出,通过 ` Executors ` 工具类可以创建多种类型的线程池,包括 :
222219
223- ![ ] ( https://oss.javaguide.cn/github/javaguide/java/concurrent/executors-inner-threadpool.png )
220+ - ` FixedThreadPool ` :固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
221+ - ` SingleThreadExecutor ` : 只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
222+ - ` CachedThreadPool ` : 可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。
223+ - ` ScheduledThreadPool ` :给定的延迟后运行任务或者定期执行任务的线程池。
224224
225225### 为什么不推荐使用内置线程池?
226226
@@ -234,9 +234,9 @@ static class Entry extends WeakReference<ThreadLocal<?>> {
234234
235235` Executors ` 返回线程池对象的弊端如下:
236236
237- - ** ` FixedThreadPool ` 和 ` SingleThreadExecutor ` ** :使用的是无界的 ` LinkedBlockingQueue ` ,任务队列最大长度为 ` Integer.MAX_VALUE ` ,可能堆积大量的请求,从而导致 OOM。
238- - ** ` CachedThreadPool ` ** :使用的是同步队列 ` SynchronousQueue ` , 允许创建的线程数量为 ` Integer.MAX_VALUE ` ,如果任务数量过多且执行速度较慢,可能会创建大量的线程,从而导致 OOM。
239- - ** ` ScheduledThreadPool ` 和 ` SingleThreadScheduledExecutor ` ** :使用的无界的延迟阻塞队列` DelayedWorkQueue ` ,任务队列最大长度为 ` Integer.MAX_VALUE ` ,可能堆积大量的请求,从而导致 OOM。
237+ - ` FixedThreadPool ` 和 ` SingleThreadExecutor ` :使用的是无界的 ` LinkedBlockingQueue ` ,任务队列最大长度为 ` Integer.MAX_VALUE ` ,可能堆积大量的请求,从而导致 OOM。
238+ - ` CachedThreadPool ` :使用的是同步队列 ` SynchronousQueue ` , 允许创建的线程数量为 ` Integer.MAX_VALUE ` ,如果任务数量过多且执行速度较慢,可能会创建大量的线程,从而导致 OOM。
239+ - ` ScheduledThreadPool ` 和 ` SingleThreadScheduledExecutor ` :使用的无界的延迟阻塞队列` DelayedWorkQueue ` ,任务队列最大长度为 ` Integer.MAX_VALUE ` ,可能堆积大量的请求,从而导致 OOM。
240240
241241``` java
242242// 无界队列 LinkedBlockingQueue
@@ -300,31 +300,31 @@ public ScheduledThreadPoolExecutor(int corePoolSize) {
300300 }
301301```
302302
303- ** ` ThreadPoolExecutor ` 3 个最重要的参数:**
303+ ` ThreadPoolExecutor ` 3 个最重要的参数:
304304
305- - ** ` corePoolSize ` :** 任务队列未达到队列容量时,最大可以同时运行的线程数量。
306- - ** ` maximumPoolSize ` :** 任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
307- - ** ` workQueue ` :** 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
305+ - ` corePoolSize ` : 任务队列未达到队列容量时,最大可以同时运行的线程数量。
306+ - ` maximumPoolSize ` : 任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
307+ - ` workQueue ` : 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
308308
309309` ThreadPoolExecutor ` 其他常见参数 :
310310
311- - ** ` keepAliveTime ` ** :线程池中的线程数量大于 ` corePoolSize ` 的时候,如果这时没有新的任务提交,多余的空闲线程不会立即销毁 ,而是会等待,直到等待的时间超过了 ` keepAliveTime ` 才会被回收销毁,线程池回收线程时,会对核心线程和非核心线程一视同仁,直到线程池中线程的数量等于 ` corePoolSize ` ,回收过程才会停止 。
312- - ** ` unit ` ** : ` keepAliveTime ` 参数的时间单位。
313- - ** ` threadFactory ` ** : executor 创建新线程的时候会用到。
314- - ** ` handler ` ** :饱和策略。关于饱和策略下面单独介绍一下 。
311+ - ` keepAliveTime ` :线程池中的线程数量大于 ` corePoolSize ` 的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁 ,而是会等待,直到等待的时间超过了 ` keepAliveTime ` 才会被回收销毁。
312+ - ` unit ` : ` keepAliveTime ` 参数的时间单位。
313+ - ` threadFactory ` : executor 创建新线程的时候会用到。
314+ - ` handler ` :饱和策略(后面会单独详细介绍一下) 。
315315
316316下面这张图可以加深你对线程池中各个参数的相互关系的理解(图片来源:《Java 性能调优实战》):
317317
318- ![ 线程池各个参数的关系] ( ./images/ java- thread-pool-summary/线程池各个参数之间的关系 .png)
318+ ![ 线程池各个参数的关系] ( https://oss.javaguide.cn/github/javaguide/ java/concurrent/relationship-between- thread-pool-parameters .png)
319319
320320### 线程池的饱和策略有哪些?
321321
322322如果当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时,` ThreadPoolExecutor ` 定义一些策略:
323323
324- - ** ` ThreadPoolExecutor.AbortPolicy ` :** 抛出 ` RejectedExecutionException ` 来拒绝新任务的处理。
325- - ** ` ThreadPoolExecutor.CallerRunsPolicy ` :** 调用执行自己的线程运行任务,也就是直接在调用` execute ` 方法的线程中运行(` run ` )被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。因此这种策略会降低对于新任务提交速度,影响程序的整体性能。如果您的应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话,你可以选择这个策略。
326- - ** ` ThreadPoolExecutor.DiscardPolicy ` :** 不处理新任务,直接丢弃掉。
327- - ** ` ThreadPoolExecutor.DiscardOldestPolicy ` :** 此策略将丢弃最早的未处理的任务请求。
324+ - ` ThreadPoolExecutor.AbortPolicy ` :抛出 ` RejectedExecutionException ` 来拒绝新任务的处理。
325+ - ` ThreadPoolExecutor.CallerRunsPolicy ` :调用执行自己的线程运行任务,也就是直接在调用` execute ` 方法的线程中运行(` run ` )被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。因此这种策略会降低对于新任务提交速度,影响程序的整体性能。如果您的应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话,你可以选择这个策略。
326+ - ` ThreadPoolExecutor.DiscardPolicy ` :不处理新任务,直接丢弃掉。
327+ - ` ThreadPoolExecutor.DiscardOldestPolicy ` :此策略将丢弃最早的未处理的任务请求。
328328
329329举个例子:Spring 通过 ` ThreadPoolTaskExecutor ` 或者我们直接通过 ` ThreadPoolExecutor ` 的构造函数创建线程池的时候,当我们不指定 ` RejectedExecutionHandler ` 饱和策略来配置线程池的时候,默认使用的是 ` AbortPolicy ` 。在这种饱和策略下,如果队列满了,` ThreadPoolExecutor ` 将抛出 ` RejectedExecutionException ` 异常来拒绝新来的任务 ,这代表你将丢失对这个任务的处理。如果不想丢弃任务的话,可以使用` CallerRunsPolicy ` 。` CallerRunsPolicy ` 和其他的几个策略不同,它既不会抛弃任务,也不会抛出异常,而是将任务回退给调用者,使用调用者的线程来执行任务
330330
@@ -354,7 +354,7 @@ public static class CallerRunsPolicy implements RejectedExecutionHandler {
354354
355355### 线程池处理任务的流程了解吗?
356356
357- ![ 图解线程池实现原理] ( https://oss.javaguide.cn/javaguide/%E5%9B%BE%E8%A7%A3%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86 .png )
357+ ![ 图解线程池实现原理] ( https://oss.javaguide.cn/github/ javaguide/java/concurrent/thread-pool-principle .png )
358358
3593591 . 如果当前运行的线程数小于核心线程数,那么就会新建一个线程来执行任务。
3603602 . 如果当前运行的线程数等于或大于核心线程数,但是小于最大线程数,那么就把该任务放入到任务队列里等待执行。
0 commit comments