Java 并发编程实战 中文版 PDF 文档
本书深入浅出地介绍了 Java 线程和并发,是一本完美的 Java 并发参考手册。书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险、构造线程安全的类及验证线程安全的规则,如何将小的线程安全类组合成更大的线程安全类,如何利用线程来提高并发应用程序的吞吐量,如何识别可并行执行的任务,如何提高单线程子系统的响应性,如何确保并发程序执行预期任务,如何提高并发代码的性能和可伸缩性等内容,最后介绍了一些高级主题,如显式锁、原子变量、非阻塞算法以及如何开发自定义的同步工具类。
前言
第 1 章 简介 1
1.1 并发简史 1
1.2 线程的优势 2
1.2.1 发挥多处理器的强大能力 2
1.2.2 建模的简单性 3
1.2.3 异步事件的简化处理 3
1.2.4 响应更灵敏的用户界面 4
1.3 线程带来的风险 4
1.3.1 安全性问题 5
1.3.2 活跃性问题 7
1.3.3 性能问题 7
1.4 线程无处不在 7
第一部分 基础知识
第 2 章 线程安全性 11
2.1 什么是线程安全性 13
2.2 原子性 14
2.2.1 竞态条件 15
2.2.2 示例:延迟初始化中的竞态条件 16
2.2.3 复合操作 17
2.3 加锁机制 18
2.3.1 内置锁 20
2.3.2 重入 21
2.4 用锁来保护状态 22
2.5 活跃性与性能 23
第 3 章 对象的共享 27
3.1 可见性 27
3.1.1 失效数据 28
3.1.2 非原子的 64 位操作 29
3.1.3 加锁与可见性 30
3.1.4 Volatile 变量 30
3.2 发布与逸出 32
3.3 线程封闭 35
3.3.1 Ad-hoc 线程封闭 35
3.3.2 栈封闭 36
3.3.3 ThreadLocal 类 37
3.4 不变性 38
3.4.1 Final 域 39
3.4.2 示例:使用 Volatile 类型来发布不可变对象 40
3.5 安全发布 41
3.5.1 不正确的发布:正确的对象被破坏 42
3.5.2 不可变对象与初始化安全性 42
3.5.3 安全发布的常用模式 43
3.5.4 事实不可变对象 44
3.5.5 可变对象 44
3.5.6 安全地共享对象 44
第 4 章 对象的组合 46
4.1 设计线程安全的类 46
4.1.1 收集同步需求 47
4.1.2 依赖状态的操作 48
4.1.3 状态的所有权 48
4.2 实例封闭 49
4.2.1 Java 监视器模式 51
4.2.2 示例:车辆追踪 51
4.3 线程安全性的委托 53
4.3.1 示例:基于委托的车辆追踪器 54
4.3.2 独立的状态变量 55
4.3.3 当委托失效时 56
4.3.4 发布底层的状态变量 57
4.3.5 示例:发布状态的车辆追踪器 58
4.4 在现有的线程安全类中添加功能 59
4.4.1 客户端加锁机制 60
4.4.2 组合 62
4.5 将同步策略文档化 62
第 5 章 基础构建模块 66
5.1 同步容器类 66
5.1.1 同步容器类的问题 66
5.1.2 迭代器与 Concurrent-ModificationException68
5.1.3 隐藏迭代器 69
5.2 并发容器 70
5.2.1 ConcurrentHashMap71
5.2.2 额外的原子 Map 操作 72
5.2.3 CopyOnWriteArrayList72
5.3 阻塞队列和生产者-消费者模式 73
5.3.1 示例:桌面搜索 75
5.3.2 串行线程封闭 76
5.3.3 双端队列与工作密取 77
5.4 阻塞方法与中断方法 77
5.5 同步工具类 78
5.5.1 闭锁 79
5.5.2 FutureTask80
5.5.3 信号量 82
5.5.4 栅栏 83
5.6 构建高效且可伸缩的结果缓存 85
第二部分 结构化并发应用程序
第 6 章 任务执行 93
6.1 在线程中执行任务 93
6.1.1 串行地执行任务 94
6.1.2 显式地为任务创建线程 94
6.1.3 无限制创建线程的不足 95
6.2 Executor 框架 96
6.2.1 示例:基于 Executor 的 Web 服务器 97
6.2.2 执行策略 98
6.2.3 线程池 98
6.2.4 Executor 的生命周期 99
6.2.5 延迟任务与周期任务 101
6.3 找出可利用的并行性 102
6.3.1 示例:串行的页面渲染器 102
6.3.2 携带结果的任务 Callable 与 Future103
6.3.3 示例:使用 Future 实现页面渲染器 104
6.3.4 在异构任务并行化中存在的局限 106
6.3.5 CompletionService:Executor 与 BlockingQueue106
6.3.6 示例:使用 CompletionService 实现页面渲染器 107
6.3.7 为任务设置时限 108
6.3.8 示例:旅行预定门户网站 109
第 7 章 取消与关闭 111
7.1 任务取消 111
7.1.1 中断 113
7.1.2 中断策略 116
7.1.3 响应中断 117
7.1.4 示例:计时运行 118
7.1.5 通过 Future 来实现取消 120
7.1.6 处理不可中断的阻塞 121
7.1.7 采用 newTaskFor 来封装非标准的取消 122
7.2 停止基于线程的服务 124
7.2.1 示例:日志服务 124
7.2.2 关闭 ExecutorService127
7.2.3 “毒丸”对象 128
7.2.4 示例:只执行一次的服务 129
7.2.5 shutdownNow 的局限性 130
7.3 处理非正常的线程终止 132
7.4 JVM 关闭 135
7.4.1 关闭钩子 135
7.4.2 守护线程 136
7.4.3 终结器 136
第 8 章 线程池的使用 138
8.1 在任务与执行策略之间的隐性耦合 138
8.1.1 线程饥饿死锁 139
8.1.2 运行时间较长的任务 140
8.2 设置线程池的大小 140
8.3 配置 ThreadPoolExecutor141
8.3.1 线程的创建与销毁 142
8.3.2 管理队列任务 142
8.3.3 饱和策略 144
8.3.4 线程工厂 146
8.3.5 在调用构造函数后再定制 ThreadPoolExecutor147
8.4 扩展 ThreadPoolExecutor148
8.5 递归算法的并行化 149
第 9 章 图形用户界面应用程序 156
9.1 为什么 GUI 是单线程的 156
9.1.1 串行事件处理 157
9.1.2 Swing 中的线程封闭机制 158
9.2 短时间的 GUI 任务 160
9.3 长时间的 GUI 任务 161
9.3.1 取消 162
9.3.2 进度标识和完成标识 163
9.3.3 SwingWorker165
9.4 共享数据模型 165
9.4.1 线程安全的数据模型 166
9.4.2 分解数据模型 166
9.5 其他形式的单线程子系统 167
第三部分 活跃性、性能与测试
第 10 章 避免活跃性危险 169
10.1 死锁 169
10.1.1 锁顺序死锁 170
10.1.2 动态的锁顺序死锁 171
10.1.3 在协作对象之间发生的死锁 174
10.1.4 开放调用 175
10.1.5 资源死锁 177
10.2 死锁的避免与诊断 178
10.2.1 支持定时的锁 178
10.2.2 通过线程转储信息来分析死锁 178
10.3 其他活跃性危险 180
10.3.1 饥饿 180
10.3.2 糟糕的响应性 181
10.3.3 活锁 181
第 11 章 性能与可伸缩性 183
11.1 对性能的思考 183
11.1.1 性能与可伸缩性 184
11.1.2 评估各种性能权衡因素 185
11.2 Amdahl 定律 186
11.2.1 示例:在各种框架中隐藏的串行部分 188
11.2.2 Amdahl 定律的应用 189
11.3 线程引入的开销 189
11.3.1 上下文切换 190
11.3.2 内存同步 190
11.3.3 阻塞 192
11.4 减少锁的竞争 192
11.4.1 缩小锁的范围(“快进快出”)193
11.4.2 减小锁的粒度 195
11.4.3 锁分段 196
11.4.4 避免热点域 197
11.4.5 一些替代独占锁的方法 198
11.4.6 监测 CPU 的利用率 199
11.4.7 向对象池说“不”200
11.5 示例:比较 Map 的性能 200
11.6 减少上下文切换的开销 201
第 12 章 并发程序的测试 204
12.1 正确性测试 205
12.1.1 基本的单元测试 206
12.1.2 对阻塞操作的测试 207
12.1.3 安全性测试 208
12.1.4 资源管理的测试 212
12.1.5 使用回调 213
12.1.6 产生更多的交替操作 214
12.2 性能测试 215
12.2.1 在 PutTakeTest 中增加计时功能 215
12.2.2 多种算法的比较 217
12.2.3 响应性衡量 218
12.3 避免性能测试的陷阱 220
12.3.1 垃圾回收 220
12.3.2 动态编译 220
12.3.3 对代码路径的不真实采样 222
12.3.4 不真实的竞争程度 222
12.3.5 无用代码的消除 223
12.4 其他的测试方法 224
12.4.1 代码审查 224
12.4.2 静态分析工具 224
12.4.3 面向方面的测试技术 226
12.4.4 分析与监测工具 226
第四部分 高级主题
第 13 章 显式锁 227
13.1 Lock 与 ReentrantLock227
13.1.1 轮询锁与定时锁 228
13.1.2 可中断的锁获取操作 230
13.1.3 非块结构的加锁 231
13.2 性能考虑因素 231
13.3 公平性 232
13.4 在 synchronized 和 ReentrantLock 之间进行选择 234
13.5 读-写锁 235
第 14 章 构建自定义的同步工具 238
14.1 状态依赖性的管理 238
14.1.1 示例:将前提条件的失败传递给调用者 240
14.1.2 示例:通过轮询与休眠来实现简单的阻塞 241
14.1.3 条件队列 243
14.2 使用条件队列 244
14.2.1 条件谓词 244
14.2.2 过早唤醒 245
14.2.3 丢失的信号 246
14.2.4 通知 247
14.2.5 示例:阀门类 248
14.2.6 子类的安全问题 249
14.2.7 封装条件队列 250
14.2.8 入口协议与出口协议 250
14.3 显式的 Condition 对象 251
14.4 Synchronizer 剖析 253
14.5 AbstractQueuedSynchronizer254
14.6 java.util.concurrent 同步器类中的 AQS257
14.6.1 ReentrantLock257
14.6.2 Semaphore 与 CountDownLatch258
14.6.3 FutureTask259
14.6.4 ReentrantReadWriteLock259
第 15 章 原子变量与非阻塞同步机制 261
15.1 锁的劣势 261
15.2 硬件对并发的支持 262
15.2.1 比较并交换 263
15.2.2 非阻塞的计数器 264
15.2.3 JVM 对 CAS 的支持 265
15.3 原子变量类 265
15.3.1 原子变量是一种“更好的 volatile”266
15.3.2 性能比较:锁与原子变量 267
15.4 非阻塞算法 270
15.4.1 非阻塞的栈 270
15.4.2 非阻塞的链表 272
15.4.3 原子的域更新器 274
15.4.4 ABA 问题 275
第 16 章 Java 内存模型 277
16.1 什么是内存模型,为什么需要它 277
16.1.1 平台的内存模型 278
16.1.2 重排序 278
16.1.3 Java 内存模型简介 280
16.1.4 借助同步 281
16.2 发布 283
16.2.1 不安全的发布 283
16.2.2 安全的发布 284
16.2.3 安全初始化模式 284
16.2.4 双重检查加锁 286
16.3 初始化过程中的安全性 287
附录 A 并发性标注 289
下载地址:https://www.wenjiangs.com/wp-content/uploads/2023/10/4lBlaQQJclpF0QYP.zip
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论