Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 22f0653

Browse files
线程池学习总结
1 parent ef58b8d commit 22f0653

File tree

2 files changed

+69
-32
lines changed

2 files changed

+69
-32
lines changed

‎docs/java/Multithread/java线程池学习总结.md‎

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,40 @@
1-
Java 面试通关手册(Java 学习指南,欢迎 Star,会一直完善下去,欢迎建议和指导):[https://github.com/Snailclimb/Java_Guide](https://github.com/Snailclimb/Java_Guide "https://github.com/Snailclimb/Java_Guide")
1+
<!-- TOC -->
2+
3+
- [一 使用线程池的好处](#一-使用线程池的好处)
4+
- [二 Executor 框架](#二-executor-框架)
5+
- [2.1 简介](#21-简介)
6+
- [2.2 Executor 框架结构(主要由三大部分组成)](#22-executor-框架结构主要由三大部分组成)
7+
- [1 任务。](#1-任务)
8+
- [2 任务的执行](#2-任务的执行)
9+
- [3 异步计算的结果](#3-异步计算的结果)
10+
- [2.3 Executor 框架的使用示意图](#23-executor-框架的使用示意图)
11+
- [三 ThreadPoolExecutor 类简单介绍(重要)](#三-threadpoolexecutor-类简单介绍重要)
12+
- [3.1 ThreadPoolExecutor 类分析](#31-threadpoolexecutor-类分析)
13+
- [3.2 推荐使用ThreadPoolExecutor 构造函数创建线程池](#32-推荐使用threadpoolexecutor-构造函数创建线程池)
14+
- [四 ThreadPoolExecutor 使用示例](#四-threadpoolexecutor-使用示例)
15+
- [4.1 示例代码](#41-示例代码)
16+
- [4.2 原理分析](#42-原理分析)
17+
- [4.3 几个常见的方法对比](#43-几个常见的方法对比)
18+
- [4.3.1 shutdown()VS shutdownNow()](#431-shutdownvs-shutdownnow)
19+
- [4.3.2 isTerminated() Vs isShutdown()](#432-isterminated-vs-isshutdown)
20+
- [五 几种常见的线程池详解](#五-几种常见的线程池详解)
21+
- [5.1 FixedThreadPool 详解](#51-fixedthreadpool-详解)
22+
- [5.2 SingleThreadExecutor 详解](#52-singlethreadexecutor-详解)
23+
- [5.3 CachedThreadPool 详解](#53-cachedthreadpool-详解)
24+
- [六 ScheduledThreadPoolExecutor 详解](#六-scheduledthreadpoolexecutor-详解)
25+
- [6.1 简介](#61-简介)
26+
- [6.2 运行机制](#62-运行机制)
27+
- [6.3 ScheduledThreadPoolExecutor 执行周期任务的步骤](#63-scheduledthreadpoolexecutor-执行周期任务的步骤)
28+
- [6.4 ScheduledThreadPoolExecutor 使用示例](#64-scheduledthreadpoolexecutor-使用示例)
29+
- [6.4.1 ScheduledExecutorService scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)方法](#641-scheduledexecutorservice-scheduleatfixedraterunnable-commandlong-initialdelaylong-periodtimeunit-unit方法)
30+
- [6.4.2 ScheduledExecutorService scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)方法](#642-scheduledexecutorservice-schedulewithfixeddelayrunnable-commandlong-initialdelaylong-delaytimeunit-unit方法)
31+
- [6.4.3 scheduleWithFixedDelay() vs scheduleAtFixedRate()](#643-schedulewithfixeddelay-vs-scheduleatfixedrate)
32+
- [七 各种线程池的适用场景介绍](#七-各种线程池的适用场景介绍)
33+
- [八 总结](#八-总结)
34+
- [九 参考](#九-参考)
35+
- [十 其他推荐阅读](#十-其他推荐阅读)
36+
37+
<!-- /TOC -->
238

339
## 一 使用线程池的好处
440

@@ -181,11 +217,11 @@ public class ScheduledThreadPoolExecutor
181217
对应 Executors 工具类中的方法如图所示:
182218
![通过Executor 框架的工具类Executors来实现](https://imgconvert.csdnimg.cn/aHR0cDovL215LWJsb2ctdG8tdXNlLm9zcy1jbi1iZWlqaW5nLmFsaXl1bmNzLmNvbS8xOC00LTE2LzEzMjk2OTAxLmpwZw?x-oss-process=image/format,png)
183219

184-
## ThreadPoolExecutor 使用示例
220+
## ThreadPoolExecutor 使用示例
185221

186222
我们上面讲解了 `Executor`框架以及 `ThreadPoolExecutor` 类,下面让我们实战一下,来通过写一个 `ThreadPoolExecutor` 的小 Demo 来回顾上面的内容。
187223

188-
### 5.1 示例代码
224+
### 4.1 示例代码
189225

190226
首先创建一个 `Runnable` 接口的实现类(当然也可以是 `Callable` 接口,我们上面也说了两者的区别是:`Runnable` 接口不会返回结果但是 `Callable` 接口可以返回结果。后面介绍 `Executors` 类的一些方法的时候会介绍到两者的相互转换。)
191227

@@ -300,7 +336,7 @@ pool-1-thread-1 End. Time = Tue Nov 12 20:59:54 CST 2019
300336
301337
```
302338

303-
### 5.2 原理分析
339+
### 4.2 原理分析
304340

305341
承接 5.1 节,我们通过代码输出结果可以看出:**线程池每次会同时执行 5 个任务,这5 个任务执行完之后,剩余的 5 个任务才会被执行。** 大家可以先通过上面讲解的内容,分析一下到底是咋回事?(自己独立思考一会)
306342

@@ -361,21 +397,21 @@ pool-1-thread-1 End. Time = Tue Nov 12 20:59:54 CST 2019
361397

362398
> 我们在代码中模拟了 10 个任务,我们配置的核心线程数为 5 、等待队列容量为 100 ,所以每次只可能存在 5 个任务同时执行,剩下的 5 个任务会被放到等待队列中去。当前的 5 个任务之行完成后,才会之行剩下的 5 个任务。
363399
364-
### 5.3 几个常见的方法对比
400+
### 4.3 几个常见的方法对比
365401

366-
#### 5.3.1 shutdown()VS shutdownNow()
402+
#### 4.3.1 shutdown()VS shutdownNow()
367403

368404
- **`shutdown()`** :关闭线程池,线程池的状态变为 `SHUTDOWN `。线程池不再接受新任务了,但是队列里的任务得执行完毕。
369405
- **`shutdownNow()`** :关闭线程池,线程的状态变为 `STOP`。线程池会终止当前正在运行的任务,并停止处理排队的任务并返回正在等待执行的 List。
370406

371-
#### 5.3.2 isTerminated() Vs isShutdown()
407+
#### 4.3.2 isTerminated() Vs isShutdown()
372408

373409
- **`isShutDown`** 当调用 `shutdown()` 方法后返回为true。
374410
- **`isTerminated`** 当调用 `shutdown()` 方法后,并且所有提交的任务完成后返回为true
375411

376-
## 几种常见的线程池详解
412+
## 几种常见的线程池详解
377413

378-
### 4.1 FixedThreadPool 详解
414+
### 5.1 FixedThreadPool 详解
379415

380416
`FixedThreadPool` 被称为可重用固定线程数的线程池。通过 Executors 类中的相关源代码来看一下相关实现:
381417

@@ -419,7 +455,7 @@ pool-1-thread-1 End. Time = Tue Nov 12 20:59:54 CST 2019
419455
3. 由于 1 和 2,使用无界队列时 keepAliveTime 将是一个无效参数;
420456
4. 运行中的 FixedThreadPool(未执行 shutdown()或 shutdownNow()方法)不会拒绝任务
421457

422-
### 3.5 SingleThreadExecutor 详解
458+
### 5.2 SingleThreadExecutor 详解
423459

424460
SingleThreadExecutor 是使用单个 worker 线程的 Executor。下面看看**SingleThreadExecutor 的实现:**
425461

@@ -462,7 +498,7 @@ SingleThreadExecutor 是使用单个 worker 线程的 Executor。下面看看**S
462498
2. 当前线程池中有一个运行的线程后,将任务加入 LinkedBlockingQueue
463499
3. 线程执行完 1 中的任务后,会在循环中反复从 LinkedBlockingQueue 中获取任务来执行;
464500

465-
### 3.6 CachedThreadPool 详解
501+
### 5.3 CachedThreadPool 详解
466502

467503
CachedThreadPool 是一个会根据需要创建新线程的线程池。下面通过源码来看看 CachedThreadPool 的实现:
468504

@@ -501,31 +537,31 @@ CachedThreadPool 的 corePoolSize 被设置为空(0),maximumPoolSize 被
501537
1. 首先执行 SynchronousQueue.offer(Runnable task)。如果当前 maximumPool 中有闲线程正在执行 SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS),那么主线程执行 offer 操作与空闲线程执行的 poll 操作配对成功,主线程把任务交给空闲线程执行,execute()方法执行完成,否则执行下面的步骤 2;
502538
2. 当初始 maximumPool 为空,或者 maximumPool 中没有空闲线程时,将没有线程执行 SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)。这种情况下,步骤 1 将失败,此时 CachedThreadPool 会创建新线程执行任务,execute 方法执行完成;
503539

504-
## ScheduledThreadPoolExecutor 详解
540+
## ScheduledThreadPoolExecutor 详解
505541

506-
### 4.1 简介
542+
### 6.1 简介
507543

508-
**ScheduledThreadPoolExecutor 主要用来在给定的延迟后运行任务,或者定期执行任务。**
544+
**`ScheduledThreadPoolExecutor` 主要用来在给定的延迟后运行任务,或者定期执行任务。**
509545

510-
**ScheduledThreadPoolExecutor 使用的任务队列 DelayQueue 封装了一个 PriorityQueue,PriorityQueue 会对队列中的任务进行排序,执行所需时间短的放在前面先被执行(ScheduledFutureTask 的 time 变量小的先执行),如果执行所需时间相同则先提交的任务将被先执行(ScheduledFutureTask 的 squenceNumber 变量小的先执行)。**
546+
**`ScheduledThreadPoolExecutor` 使用的任务队列 `DelayQueue` 封装了一个 `PriorityQueue`,`PriorityQueue` 会对队列中的任务进行排序,执行所需时间短的放在前面先被执行(`ScheduledFutureTask``time` 变量小的先执行),如果执行所需时间相同则先提交的任务将被先执行(`ScheduledFutureTask``squenceNumber` 变量小的先执行)。**
511547

512-
**ScheduledThreadPoolExecutor 和 Timer 的比较:**
548+
**`ScheduledThreadPoolExecutor``Timer` 的比较:**
513549

514-
- Timer 对系统时钟的变化敏感,ScheduledThreadPoolExecutor 不是;
515-
- Timer 只有一个执行线程,因此长时间运行的任务可以延迟其他任务。 ScheduledThreadPoolExecutor 可以配置任意数量的线程。 此外,如果你想(通过提供 ThreadFactory),你可以完全控制创建的线程;
516-
- 在 TimerTask 中抛出的运行时异常会杀死一个线程,从而导致 Timer 死机:-( ...即计划任务将不再运行。ScheduledThreadExecutor 不仅捕获运行时异常,还允许您在需要时处理它们(通过重写 afterExecute 方法 ThreadPoolExecutor)。抛出异常的任务将被取消,但其他任务将继续运行。
550+
- `Timer` 对系统时钟的变化敏感,`ScheduledThreadPoolExecutor `不是;
551+
- `Timer` 只有一个执行线程,因此长时间运行的任务可以延迟其他任务。 `ScheduledThreadPoolExecutor` 可以配置任意数量的线程。 此外,如果你想(通过提供 ThreadFactory),你可以完全控制创建的线程;
552+
-` TimerTask` 中抛出的运行时异常会杀死一个线程,从而导致 `Timer` 死机:-( ...即计划任务将不再运行。`ScheduledThreadExecutor` 不仅捕获运行时异常,还允许您在需要时处理它们(通过重写 `afterExecute` 方法` ThreadPoolExecutor`)。抛出异常的任务将被取消,但其他任务将继续运行。
517553

518554
**综上,在 JDK1.5 之后,你没有理由再使用 Timer 进行任务调度了。**
519555

520556
> **备注:** Quartz 是一个由 java 编写的任务调度库,由 OpenSymphony 组织开源出来。在实际项目开发中使用 Quartz 的还是居多,比较推荐使用 Quartz。因为 Quartz 理论上能够同时对上万个任务进行调度,拥有丰富的功能特性,包括任务调度、任务持久化、可集群化、插件等等。
521557
522-
### 4.2 ScheduledThreadPoolExecutor 运行机制
558+
### 6.2 运行机制
523559

524560
![ScheduledThreadPoolExecutor运行机制](https://imgconvert.csdnimg.cn/aHR0cDovL215LWJsb2ctdG8tdXNlLm9zcy1jbi1iZWlqaW5nLmFsaXl1bmNzLmNvbS8xOC00LTE2LzkyNTk0Njk4LmpwZw?x-oss-process=image/format,png)
525561

526-
**ScheduledThreadPoolExecutor 的执行主要分为两大部分:**
562+
**`ScheduledThreadPoolExecutor` 的执行主要分为两大部分:**
527563

528-
1. 当调用 ScheduledThreadPoolExecutor 的 **scheduleAtFixedRate()** 方法或者**scheduleWirhFixedDelay()** 方法时,会向 ScheduledThreadPoolExecutor 的 **DelayQueue** 添加一个实现了 **RunnableScheduledFutur** 接口的 **ScheduledFutureTask**
564+
1. 当调用 `ScheduledThreadPoolExecutor`**`scheduleAtFixedRate()`** 方法或者**`scheduleWirhFixedDelay()`** 方法时,会向 `ScheduledThreadPoolExecutor`**`DelayQueue`** 添加一个实现了 **`RunnableScheduledFuture`** 接口的 **`ScheduledFutureTask`**
529565
2. 线程池中的线程从 DelayQueue 中获取 ScheduledFutureTask,然后执行任务。
530566

531567
**ScheduledThreadPoolExecutor 为了实现周期性的执行任务,对 ThreadPoolExecutor 做了如下修改:**
@@ -534,7 +570,7 @@ CachedThreadPool 的 corePoolSize 被设置为空(0),maximumPoolSize 被
534570
- 获取任务的方不同
535571
- 执行周期任务后,增加了额外的处理
536572

537-
### 4.3 ScheduledThreadPoolExecutor 执行周期任务的步骤
573+
### 6.3 ScheduledThreadPoolExecutor 执行周期任务的步骤
538574

539575
![ScheduledThreadPoolExecutor执行周期任务的步骤](https://imgconvert.csdnimg.cn/aHR0cDovL215LWJsb2ctdG8tdXNlLm9zcy1jbi1iZWlqaW5nLmFsaXl1bmNzLmNvbS8xOC01LTMwLzU5OTE2Mzg5LmpwZw?x-oss-process=image/format,png)
540576

@@ -543,7 +579,7 @@ CachedThreadPool 的 corePoolSize 被设置为空(0),maximumPoolSize 被
543579
3. 线程 1 修改 ScheduledFutureTask 的 time 变量为下次将要被执行的时间;
544580
4. 线程 1 把这个修改 time 之后的 ScheduledFutureTask 放回 DelayQueue 中(DelayQueue.add())。
545581

546-
### 4.4 ScheduledThreadPoolExecutor 使用示例
582+
### 6.4 ScheduledThreadPoolExecutor 使用示例
547583

548584
1. 创建一个简单的实现 Runnable 接口的类(我们上面的例子已经实现过)
549585

@@ -596,7 +632,7 @@ Current Time = Wed May 30 17:11:49 CST 2018
596632
Finished all threads
597633
```
598634

599-
#### 4.4.1 ScheduledExecutorService scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)方法
635+
#### 6.4.1 ScheduledExecutorService scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)方法
600636

601637
我们可以使用 ScheduledExecutorService scheduleAtFixedRate 方法来安排任务在初始延迟后运行,然后在给定的时间段内运行。
602638

@@ -645,7 +681,7 @@ Process finished with exit code 0
645681
646682
```
647683

648-
#### 4.4.2 ScheduledExecutorService scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)方法
684+
#### 6.4.2 ScheduledExecutorService scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)方法
649685

650686
ScheduledExecutorService scheduleWithFixedDelay 方法可用于以初始延迟启动周期性执行,然后以给定延迟执行。 延迟时间是线程完成执行的时间。
651687

@@ -700,15 +736,15 @@ pool-1-thread-2 End. Time = Wed May 30 17:58:46 CST 2018
700736
Finished all threads
701737
```
702738

703-
#### 4.4.3 scheduleWithFixedDelay() vs scheduleAtFixedRate()
739+
#### 6.4.3 scheduleWithFixedDelay() vs scheduleAtFixedRate()
704740

705741
scheduleAtFixedRate(...)将延迟视为两个任务开始之间的差异(即定期调用)
706742
scheduleWithFixedDelay(...)将延迟视为一个任务结束与下一个任务开始之间的差异
707743

708744
> **scheduleAtFixedRate():** 创建并执行在给定的初始延迟之后,随后以给定的时间段首先启用的周期性动作; 那就是执行将在 initialDelay 之后开始,然后 initialDelay+period ,然后是 initialDelay + 2 \* period ,等等。 如果任务的执行遇到异常,则后续的执行被抑制。 否则,任务将仅通过取消或终止执行人终止。 如果任务执行时间比其周期长,则后续执行可能会迟到,但不会同时执行。
709745
> **scheduleWithFixedDelay() :** 创建并执行在给定的初始延迟之后首先启用的定期动作,随后在一个执行的终止和下一个执行的开始之间给定的延迟。 如果任务的执行遇到异常,则后续的执行被抑制。 否则,任务将仅通过取消或终止执行终止。
710746
711-
## 各种线程池的适用场景介绍
747+
## 各种线程池的适用场景介绍
712748

713749
- **FixedThreadPool:** 适用于为了满足资源管理需求,而需要限制当前线程数量的应用场景。它适用于负载比较重的服务器;
714750

@@ -720,19 +756,20 @@ scheduleWithFixedDelay(...)将延迟视为一个任务结束与下一个任
720756

721757
**SingleThreadScheduledExecutor:** 适用于需要单个后台线程执行周期任务,同时保证顺序地执行各个任务的应用场景。
722758

723-
## 总结
759+
## 总结
724760

725761
本节只是简单的介绍了一下使用线程池的好处,然后花了大量篇幅介绍 Executor 框架。详细介绍了 Executor 框架中 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor,并且通过实例详细讲解了 ScheduledThreadPoolExecutor 的使用。对于 FutureTask 只是粗略带过,因为篇幅问题,并没有深究它的原理,后面的文章会进行补充。这一篇文章只是大概带大家过一下线程池的基本概览,深入讲解的地方不是很多,后续会通过源码深入研究其中比较重要的一些知识点。
726762

727763
最后,就是这两周要考试了,会抽点时间出来简单应付一下学校考试了。然后,就是写这篇多线程的文章废了好多好多时间。一直不知从何写起。
728764

729-
## 参考
765+
## 参考
730766

731767
- 《Java 并发编程的艺术》
732768
- [Java Scheduler ScheduledExecutorService ScheduledThreadPoolExecutor Example](https://www.journaldev.com/2340/java-scheduler-scheduledexecutorservice-scheduledthreadpoolexecutor-example "Java Scheduler ScheduledExecutorService ScheduledThreadPoolExecutor Example")
733769
- [java.util.concurrent.ScheduledThreadPoolExecutor Example](https://examples.javacodegeeks.com/core-java/util/concurrent/scheduledthreadpoolexecutor/java-util-concurrent-scheduledthreadpoolexecutor-example/ "java.util.concurrent.ScheduledThreadPoolExecutor Example")
734770
- [ThreadPoolExecutor – Java Thread Pool Example](https://www.journaldev.com/1069/threadpoolexecutor-java-thread-pool-example-executorservice "ThreadPoolExecutor – Java Thread Pool Example")
735771

736-
## 其他推荐阅读
772+
## 其他推荐阅读
737773

738-
- [Java并发(三)线程池原理](https://www.cnblogs.com/warehouse/p/10720781.html)
774+
- [Java并发(三)线程池原理](https://www.cnblogs.com/warehouse/p/10720781.html)
775+
- [如何优雅的使用和理解线程池](https://github.com/crossoverJie/JCSprout/blob/master/MD/ThreadPoolExecutor.md)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /