|
3 | 3 | <!-- TOC depthFrom:2 depthTo:3 --> |
4 | 4 |
|
5 | 5 | - [第 1 章 简介](#第-1-章-简介) |
6 | | - - [1.1 并发简史](#11-并发简史) |
7 | | - - [1.2 线程的优势](#12-线程的优势) |
8 | | - - [1.3 线程带来的风险](#13-线程带来的风险) |
9 | | - - [1.4 线程无处不在](#14-线程无处不在) |
| 6 | + - [1.1 并发简史](#11-并发简史) |
| 7 | + - [1.2 线程的优势](#12-线程的优势) |
| 8 | + - [1.3 线程带来的风险](#13-线程带来的风险) |
| 9 | + - [1.4 线程无处不在](#14-线程无处不在) |
10 | 10 | - [第 2 章 线程安全性](#第-2-章-线程安全性) |
11 | | - - [2.1 什么是线程安全性](#21-什么是线程安全性) |
12 | | - - [2.2 原子性](#22-原子性) |
13 | | - - [2.3 加锁机制](#23-加锁机制) |
14 | | - - [2.4 用锁来保护状态](#24-用锁来保护状态) |
15 | | - - [2.5 活跃性与性能](#25-活跃性与性能) |
| 11 | + - [2.1 什么是线程安全性](#21-什么是线程安全性) |
| 12 | + - [2.2 原子性](#22-原子性) |
| 13 | + - [2.3 加锁机制](#23-加锁机制) |
| 14 | + - [2.4 用锁来保护状态](#24-用锁来保护状态) |
| 15 | + - [2.5 活跃性与性能](#25-活跃性与性能) |
16 | 16 | - [第 3 章 对象的共享](#第-3-章-对象的共享) |
17 | | - - [3.1 可见性](#31-可见性) |
18 | | - - [3.2 发布与逸出](#32-发布与逸出) |
19 | | - - [3.3 线程封闭](#33-线程封闭) |
20 | | - - [3.4 不变性](#34-不变性) |
21 | | - - [3.5 安全发布](#35-安全发布) |
| 17 | + - [3.1 可见性](#31-可见性) |
| 18 | + - [3.2 发布与逸出](#32-发布与逸出) |
| 19 | + - [3.3 线程封闭](#33-线程封闭) |
| 20 | + - [3.4 不变性](#34-不变性) |
| 21 | + - [3.5 安全发布](#35-安全发布) |
22 | 22 | - [第 4 章 对象的组合](#第-4-章-对象的组合) |
23 | | - - [4.1 设计线程安全的类](#41-设计线程安全的类) |
24 | | - - [4.2 实例封闭](#42-实例封闭) |
25 | | - - [4.3 线程安全性的委托](#43-线程安全性的委托) |
26 | | - - [4.4 在现有的线程安全类中添加功能](#44-在现有的线程安全类中添加功能) |
27 | | - - [4.5 将同步策略文档化](#45-将同步策略文档化) |
| 23 | + - [4.1 设计线程安全的类](#41-设计线程安全的类) |
| 24 | + - [4.2 实例封闭](#42-实例封闭) |
| 25 | + - [4.3 线程安全性的委托](#43-线程安全性的委托) |
| 26 | + - [4.4 在现有的线程安全类中添加功能](#44-在现有的线程安全类中添加功能) |
| 27 | + - [4.5 将同步策略文档化](#45-将同步策略文档化) |
28 | 28 | - [第 5 章 基础构建模块](#第-5-章-基础构建模块) |
29 | | - - [5.1 同步容器类](#51-同步容器类) |
30 | | - - [5.2 并发容器](#52-并发容器) |
31 | | - - [5.3 阻塞队列和生产者-消费者模式](#53-阻塞队列和生产者-消费者模式) |
32 | | - - [5.4 阻塞方法与中断方法](#54-阻塞方法与中断方法) |
33 | | - - [5.5 同步工具类](#55-同步工具类) |
34 | | - - [5.6 构建高效且可伸缩的结果缓存](#56-构建高效且可伸缩的结果缓存) |
| 29 | + - [5.1 同步容器类](#51-同步容器类) |
| 30 | + - [5.2 并发容器](#52-并发容器) |
| 31 | + - [5.3 阻塞队列和生产者-消费者模式](#53-阻塞队列和生产者-消费者模式) |
| 32 | + - [5.4 阻塞方法与中断方法](#54-阻塞方法与中断方法) |
| 33 | + - [5.5 同步工具类](#55-同步工具类) |
| 34 | + - [5.6 构建高效且可伸缩的结果缓存](#56-构建高效且可伸缩的结果缓存) |
35 | 35 | - [第 6 章 任务执行](#第-6-章-任务执行) |
36 | | - - [6.1 在线程中执行任务](#61-在线程中执行任务) |
37 | | - - [6.2 Executor 框架](#62-executor-框架) |
38 | | - - [6.3 找出可利用的并行性](#63-找出可利用的并行性) |
| 36 | + - [6.1 在线程中执行任务](#61-在线程中执行任务) |
| 37 | + - [6.2 Executor 框架](#62-executor-框架) |
| 38 | + - [6.3 找出可利用的并行性](#63-找出可利用的并行性) |
39 | 39 | - [第 7 章 取消与关闭](#第-7-章-取消与关闭) |
40 | | - - [7.1 任务取消](#71-任务取消) |
41 | | - - [7.2 停止基于线程的服务](#72-停止基于线程的服务) |
42 | | - - [7.3 处理非正常的线程终止](#73-处理非正常的线程终止) |
43 | | - - [7.4 JVM 关闭](#74-jvm-关闭) |
| 40 | + - [7.1 任务取消](#71-任务取消) |
| 41 | + - [7.2 停止基于线程的服务](#72-停止基于线程的服务) |
| 42 | + - [7.3 处理非正常的线程终止](#73-处理非正常的线程终止) |
| 43 | + - [7.4 JVM 关闭](#74-jvm-关闭) |
44 | 44 | - [第 8 章 线程池的使用](#第-8-章-线程池的使用) |
45 | | - - [8.1 在任务与执行策略之间的隐性耦合](#81-在任务与执行策略之间的隐性耦合) |
46 | | - - [8.2 设置线程池的大小](#82-设置线程池的大小) |
47 | | - - [8.3 配置 ThreadPoolExecutor](#83-配置-threadpoolexecutor) |
48 | | - - [8.4 扩展 ThreadPoolExecutor](#84-扩展-threadpoolexecutor) |
49 | | - - [8.5 递归算法的并行化](#85-递归算法的并行化) |
| 45 | + - [8.1 在任务与执行策略之间的隐性耦合](#81-在任务与执行策略之间的隐性耦合) |
| 46 | + - [8.2 设置线程池的大小](#82-设置线程池的大小) |
| 47 | + - [8.3 配置 ThreadPoolExecutor](#83-配置-threadpoolexecutor) |
| 48 | + - [8.4 扩展 ThreadPoolExecutor](#84-扩展-threadpoolexecutor) |
| 49 | + - [8.5 递归算法的并行化](#85-递归算法的并行化) |
50 | 50 | - [第 9 章 图形用户界面应用程序](#第-9-章-图形用户界面应用程序) |
51 | 51 | - [第 10 章 避免活跃性危险](#第-10-章-避免活跃性危险) |
52 | | - - [10.1 死锁](#101-死锁) |
53 | | - - [10.2 死锁的避免与诊断](#102-死锁的避免与诊断) |
54 | | - - [10.3 其他活跃性危险](#103-其他活跃性危险) |
| 52 | + - [10.1 死锁](#101-死锁) |
| 53 | + - [10.2 死锁的避免与诊断](#102-死锁的避免与诊断) |
| 54 | + - [10.3 其他活跃性危险](#103-其他活跃性危险) |
55 | 55 | - [第 11 章 性能与可伸缩性](#第-11-章-性能与可伸缩性) |
56 | | - - [11.1 对性能的思考](#111-对性能的思考) |
57 | | - - [11.2 Amdahl 定律](#112-amdahl-定律) |
58 | | - - [11.3 线程引入的开销](#113-线程引入的开销) |
59 | | - - [11.4 减少锁的竞争](#114-减少锁的竞争) |
60 | | - - [11.5 示例:比较 Map 的性能](#115-示例比较-map-的性能) |
61 | | - - [11.6 减少上下文切换的开销](#116-减少上下文切换的开销) |
| 56 | + - [11.1 对性能的思考](#111-对性能的思考) |
| 57 | + - [11.2 Amdahl 定律](#112-amdahl-定律) |
| 58 | + - [11.3 线程引入的开销](#113-线程引入的开销) |
| 59 | + - [11.4 减少锁的竞争](#114-减少锁的竞争) |
| 60 | + - [11.5 示例:比较 Map 的性能](#115-示例比较-map-的性能) |
| 61 | + - [11.6 减少上下文切换的开销](#116-减少上下文切换的开销) |
62 | 62 | - [第 12 章 并发程序的测试](#第-12-章-并发程序的测试) |
63 | | - - [12.1 正确性测试](#121-正确性测试) |
64 | | - - [12.2 性能测试](#122-性能测试) |
65 | | - - [12.3 避免性能测试的陷阱](#123-避免性能测试的陷阱) |
66 | | - - [12.4 其他的测试方法](#124-其他的测试方法) |
| 63 | + - [12.1 正确性测试](#121-正确性测试) |
| 64 | + - [12.2 性能测试](#122-性能测试) |
| 65 | + - [12.3 避免性能测试的陷阱](#123-避免性能测试的陷阱) |
| 66 | + - [12.4 其他的测试方法](#124-其他的测试方法) |
67 | 67 | - [第 13 章 显式锁](#第-13-章-显式锁) |
68 | | - - [13.1 Lock 与 ReentrantLock](#131-lock-与-reentrantlock) |
69 | | - - [13.2 性能考虑因素](#132-性能考虑因素) |
70 | | - - [13.3 公平性](#133-公平性) |
71 | | - - [13.4 在 synchronized 和 ReentrantLock 之间进行选择](#134-在-synchronized-和-reentrantlock-之间进行选择) |
72 | | - - [13.5 读-写锁](#135-读-写锁) |
| 68 | + - [13.1 Lock 与 ReentrantLock](#131-lock-与-reentrantlock) |
| 69 | + - [13.2 性能考虑因素](#132-性能考虑因素) |
| 70 | + - [13.3 公平性](#133-公平性) |
| 71 | + - [13.4 在 synchronized 和 ReentrantLock 之间进行选择](#134-在-synchronized-和-reentrantlock-之间进行选择) |
| 72 | + - [13.5 读-写锁](#135-读-写锁) |
73 | 73 | - [第 14 章 构建自定义的同步工具](#第-14-章-构建自定义的同步工具) |
74 | | - - [14.1 状态依赖性的管理](#141-状态依赖性的管理) |
75 | | - - [14.2 使用条件队列](#142-使用条件队列) |
76 | | - - [14.3 显式的 Condition 对象](#143-显式的-condition-对象) |
77 | | - - [14.4 Synchronizer 剖析](#144-synchronizer-剖析) |
78 | | - - [14.5 AbstractQueuedSynchronizer](#145-abstractqueuedsynchronizer) |
79 | | - - [14.6 java.util.concurrent 同步器类中的 AQS](#146-javautilconcurrent-同步器类中的-aqs) |
| 74 | + - [14.1 状态依赖性的管理](#141-状态依赖性的管理) |
| 75 | + - [14.2 使用条件队列](#142-使用条件队列) |
| 76 | + - [14.3 显式的 Condition 对象](#143-显式的-condition-对象) |
| 77 | + - [14.4 Synchronizer 剖析](#144-synchronizer-剖析) |
| 78 | + - [14.5 AbstractQueuedSynchronizer](#145-abstractqueuedsynchronizer) |
| 79 | + - [14.6 java.util.concurrent 同步器类中的 AQS](#146-javautilconcurrent-同步器类中的-aqs) |
80 | 80 | - [第 15 章 原子变量与非阻塞同步机制](#第-15-章-原子变量与非阻塞同步机制) |
81 | | - - [15.1 锁的劣势](#151-锁的劣势) |
82 | | - - [15.2 硬件对并发的支持](#152-硬件对并发的支持) |
83 | | - - [15.3 原子变量类](#153-原子变量类) |
84 | | - - [15.4 非阻塞算法](#154-非阻塞算法) |
| 81 | + - [15.1 锁的劣势](#151-锁的劣势) |
| 82 | + - [15.2 硬件对并发的支持](#152-硬件对并发的支持) |
| 83 | + - [15.3 原子变量类](#153-原子变量类) |
| 84 | + - [15.4 非阻塞算法](#154-非阻塞算法) |
85 | 85 | - [第 16 章 Java 内存模型](#第-16-章-java-内存模型) |
86 | | - - [16.1 什么是内存模型,为什么需要它](#161-什么是内存模型为什么需要它) |
87 | | - - [16.2 发布](#162-发布) |
88 | | - - [16.3 初始化过程中的安全性](#163-初始化过程中的安全性) |
| 86 | + - [16.1 什么是内存模型,为什么需要它](#161-什么是内存模型为什么需要它) |
| 87 | + - [16.2 发布](#162-发布) |
| 88 | + - [16.3 初始化过程中的安全性](#163-初始化过程中的安全性) |
89 | 89 |
|
90 | 90 | <!-- /TOC --> |
91 | 91 |
|
@@ -155,58 +155,67 @@ Java 提供了一种内置的锁机制来支持原子性:synchronized。 |
155 | 155 |
|
156 | 156 | ### 3.1 可见性 |
157 | 157 |
|
158 | | -* 3.1.1 失效数据 |
159 | | -* 3.1.2 非原子的 64 位操作 |
160 | | -* 3.1.3 加锁与可见性 |
161 | | -* 3.1.4 Volatile 变量 |
| 158 | +* 在没有同步的情况下,编译器、处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整。 |
| 159 | +* 内置锁可以用于确保某个线程以一种可预测的方式来查看另一个线程的执行结果。 |
| 160 | +* 加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。 |
| 161 | +* volatile 变量是一种稍弱的同步机制。 |
| 162 | +* 当把变量声明为 volatile 类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile 变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取 volatile 类型的变量时总会返回最新写入的值。 |
| 163 | +* 访问 volatile 变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此 volatile 变量是一种比 synchronized 关键字更轻量级的同步机制。 |
| 164 | +* 仅当 volatile 变量能简化代码的实现以及对同步策略的验证时,才应该使用它们。 |
| 165 | +* 加锁机制既可以确保可见性又可以确保原子性,而 volatile 变量只能确保可见性。 |
| 166 | +* 当且仅当满足以下所有条件时,才应该使用 volatile 变量 |
| 167 | + * 对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。 |
| 168 | + * 该变量不会与其他状态变量一起纳入不变性条件中。 |
| 169 | + * 在访问变量时不需要加锁。 |
162 | 170 |
|
163 | 171 | ### 3.2 发布与逸出 |
164 | 172 |
|
165 | 173 | ### 3.3 线程封闭 |
166 | 174 |
|
167 | | -* 3.3.1 Ad-hoc 线程封闭 |
168 | | -* 3.3.2 栈封闭 |
169 | | -* 3.3.3 ThreadLocal 类 |
| 175 | +* 栈封闭:只能通过局部变量才能访问对象。 |
| 176 | +* ThreadLocal 类能使线程中的某个值与保存值得对象关联起来。ThreadLoacl 提供了 get 与 set 等访问接口或方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此 get 宗师返回由当前执行线程在调用 set 时设置的最新值。 |
| 177 | +* ThreadLocal 对象通常用于防止对可变的单实例变量或全局变量进行共享。 |
170 | 178 |
|
171 | 179 | ### 3.4 不变性 |
172 | 180 |
|
173 | | -* 3.4.1 Final 域 |
174 | | -* 3.4.2 示例:使用 Volatile 类型来发布不可变对象 |
| 181 | +* 不可变对象一定是线程安全的。 |
| 182 | +* 满足以下条件的对象才是可变的: |
| 183 | + * 对象创建以后其状态就不能修改。 |
| 184 | + * 对象的所有域都是 final 类型。 |
| 185 | + * 对象是正确创建的(在对象的创建期间,this 引用没有逸出)。 |
175 | 186 |
|
176 | 187 | ### 3.5 安全发布 |
177 | 188 |
|
178 | | -* 3.5.1 不正确的发布:正确的对象被破坏 |
179 | | -* 3.5.2 不可变对象与初始化安全性 |
180 | | -* 3.5.3 安全发布的常用模式 |
181 | | -* 3.5.4 事实不可变对象 |
182 | | -* 3.5.5 可变对象 |
183 | | -* 3.5.6 安全地共享对象 |
| 189 | +* 在没有额外的同步的情况下,任何线程都可以安全地使用被安全发布的事实不可变对象。 |
| 190 | +* 对于可变对象,不仅在发布对象时需要使用同步,并且在每次对象访问时同样需要使用同步来确保后续修改操作的可见性。 |
| 191 | +* 在并发程序中使用和共享对象时,可以使用一些实用的策略,包括: |
| 192 | +* 线程封闭。线程封闭的对象只能由一个线程拥有,对象被封闭在该线程中,并且只能由这个线程修改。 |
| 193 | +* 只读共享。在没有额外同步的情况下,共享的只读对象可以由多个线程并发访问。 |
| 194 | +* 线程安全共享。线程安全的对象在其内部实现同步,因此多个线程可以通过对象的共有接口来进行访问而不需要进一步的同步。 |
| 195 | +* 保护对象。被保护的对象只能通过持有特定的锁来访问。保护对象包括封装在其他线程安全对象中的对象,以及已发布的并且由某个特定锁保护的对象。 |
184 | 196 |
|
185 | 197 | ## 第 4 章 对象的组合 |
186 | 198 |
|
187 | 199 | ### 4.1 设计线程安全的类 |
188 | 200 |
|
189 | | -* 4.1.1 收集同步需求 |
190 | | -* 4.1.2 依赖状态的操作 |
191 | | -* 4.1.3 状态的所有权 |
| 201 | +* 设计线程安全类的过程中,需要包含三个基本要素: |
| 202 | + * 找出构成对象状态的所有变量。 |
| 203 | + * 找出约束状态变量的不变性条件。 |
| 204 | + * 建立对象状态的并发访问管理策略。 |
| 205 | +* 类的不变性条件与后验条件约束力在对象上有哪些状态和状态转换是有效的。 |
192 | 206 |
|
193 | 207 | ### 4.2 实例封闭 |
194 | 208 |
|
195 | | -* 4.2.1 Java 监视器模式 |
196 | | -* 4.2.2 示例:车辆追踪 |
| 209 | +* 将数据封装在对象内部,可以将数据的访问限制在对象的方法上,从而更易确保线程在访问数据时总能持有正确的锁。 |
| 210 | +* 封闭机制更易于构造线程安全的类,因为当封闭类的状态时,在分析类的线程安全性时就无需检查整个程序。 |
197 | 211 |
|
198 | 212 | ### 4.3 线程安全性的委托 |
199 | 213 |
|
200 | | -* 4.3.1 示例:基于委托的车辆追踪器 |
201 | | -* 4.3.2 独立的状态变量 |
202 | | -* 4.3.3 当委托失效时 |
203 | | -* 4.3.4 发布底层的状态变量 |
204 | | -* 4.3.5 示例:发布状态的车辆追踪器 |
| 214 | +* 如果一个类是由多个独立且线程安全的状态变量组成,并且在所有的操作中都不包含无效状态转换,那么可以将线程安全性委托给底层的状态变量。 |
205 | 215 |
|
206 | | -### 4.4 在现有的线程安全类中添加功能 |
| 216 | +* 如果一个状态变量是线程安全的,并且没有任何不变性条件来约束它的值,在变量的操作上也不存在任何不允许的状态转换,那么就可以安全地发布这个变量。 |
207 | 217 |
|
208 | | -* 4.4.1 客户端加锁机制 |
209 | | -* 4.4.2 组合 |
| 218 | +### 4.4 在现有的线程安全类中添加功能 |
210 | 219 |
|
211 | 220 | ### 4.5 将同步策略文档化 |
212 | 221 |
|
|
0 commit comments