《JAVA并发编程实践》PDF下载

  • 购买积分:14 如何计算积分?
  • 作  者:(美)Brian Goetz等著;韩锴,方妙译
  • 出 版 社:北京:电子工业出版社
  • 出版年份:2007
  • ISBN:7121043165
  • 页数:403 页
图书介绍:随着多核处理器的普及,使用并发成为构建高性能应用程序的关键。Java 5以及6在开发并发程序取得了显著的进步,提高了Java虚拟机的性能,提高了并发类的可伸缩性,并加入了丰富的新并发构建块。在本书中,这些便利工具的创造者不仅解释了它们究竟如何工作、如何使用,同时,还阐释了创造它们的原因,及其背后的设计模式。本书既能够成为读者的理论支持,又可以作为构建可靠的,可伸缩的,可维护的并发程序的技术支持。本书并不仅仅提供并发API的清单及其机制,本书还提供了设计原则,模式和思想模型,使我们能够更好地构建正确的,性能良好的并发程序。本书的读者是那些具有一定Java编程经验的程序员、希望了解Java SE 5,6在线程技术上的改进和新特性的程序员,以及Java和并发编程的爱好者。

第1章 介绍 1

1.1 并发的(非常)简短历史 1

1.2 线程的优点 3

1.3 线程的风险 5

1.4 线程无处不在 9

第1部分 基础 13

第2章 线程安全 15

2.1 什么是线程安全性 17

2.2 原子性 19

2.3 锁 23

2.4 用锁来保护状态 27

2.5 活跃度与性能 29

第3章 共享对象 33

3.1 可见性 33

3.2 发布和逸出 39

3.3 线程封闭 42

3.4 不可变性 46

3.5 安全发布 49

第4章 组合对象 55

4.1 设计线程安全的类 55

4.2 实例限制 58

4.3 委托线程安全 62

4.4 向已有的线程安全类添加功能 71

4.5 同步策略的文档化 74

第5章 构建块 79

5.1 同步容器 79

5.2 并发容器 84

5.3 阻塞队列和生产者-消费者模式 87

5.4 阻塞和可中断的方法 92

5.5 Synchronizer 94

5.6 为计算结果建立高效、可伸缩的高速缓存 101

第2部分 构建并发应用程序 111

第6章 任务执行 113

6.1 在线程中执行任务 113

6.2 Executor框架 117

6.3 寻找可强化的并行性 123

第7章 取消和关闭 135

7.1 任务取消 135

7.2 停止基于线程的服务 150

7.3 处理反常的线程终止 161

7.4 JVM关闭 164

第8章 应用线程池 167

8.1 任务与执行策略间的隐性耦合 167

8.2 定制线程池的大小 170

8.3 配置ThreadPoolExecutor 171

8.4 扩展ThreadPoolExecutor 179

8.5 并行递归算法 181

第9章 GUI应用程序 189

9.1 为什么GUI是单线程化的 189

9.2 短期的GUI任务 192

9.3 耗时GUI任务 195

9.4 共享数据模型 198

9.5 其他形式的单线程子系统 202

第3部分 活跃度,性能和测试 203

第10章 避免活跃度危险 205

10.1 死锁 205

10.2 避免和诊断死锁 215

10.3 其他的活跃度危险 218

第11章 性能和可伸缩性 221

11.1 性能的思考 221

11.2 Amdahl定律 225

11.3 线程引入的开销 229

11.4 减少锁的竞争 232

11.5 示例:比较Map的性能 242

11.6 减少上下文切换的开销 243

第12章 测试并发程序 247

12.1 测试正确性 248

12.2 测试性能 260

12.3 避免性能测试的陷阱 266

12.4 测试方法补遗 270

第4部分 高级主题 275

第13章 显式锁 277

13.1 Lock和ReentrantLock 277

13.2 对性能的考量 282

13.3 公平性 283

13.4 在synchronized和ReentrantLock之间进行选择 285

13.5 读-写锁 286

第14章 构建自定义的同步工具 291

14.1 管理状态依赖性 291

14.2 使用条件队列 298

14.3 显式的Condition对象 306

14.4 剖析Synchronizer 308

14.5 AbstractQueuedSynchronizer 311

14.6 java.util.concurrent的Synchronizer类中的AQS 314

第15章 原子变量与非阻塞同步机制 319

15.1 锁的劣势 319

15.2 硬件对并发的支持 321

15.3 原子变量类 324

15.4 非阻塞算法 329

第16章 Java存储模型 337

16.1 什么是存储模型,要它何用 337

16.2 发布 344

16.3 初始化安全性 349

附录A 同步Annotation 353

A.1 类Annotation 353

A.2 域Annotation和方法Annotation 353

参考文献 355

索引 359

代码清单 6

清单1.1 非线程安全的序列生成器 6

清单1.2 线程安全的序列生成器 7

清单2.1 一个无状态的Servlet 18

清单2.2 Servlet计算请求数量而没有必要的同步(不要这样做) 19

清单2.3 惰性初始化中存在竞争条件(不要这样做) 21

清单2.4 Servlet使用AtomicLong统计请求数 23

清单2.5 没有正确原子化的Servlet试图缓存它的最新结果(不要这样做) 24

清单2.6 缓存了最新结果的servlet,但响应性令人无法接受(不要这样做) 26

清单2.7 如果内部锁不是可重入的,代码将死锁 27

清单2.8 缓存最新请求和结果的servlet 31

清单3.1 在没有同步的情况下共享变量(不要这样做) 34

清单3.2 非线程安全的可变整数访问器 36

清单3.3 线程安全的可变整数访问器 36

清单3.4 数绵羊 39

清单3.5 发布对象 40

清单3.6 允许内部可变的数据逸出(不要这样做) 40

清单3.7 隐式地允许this引用逸出(不要这样做) 41

清单3.8 使用工厂方法防止this引用在构造期间逸出 42

清单3.9 本地的基本类型和引用类型的变量的线程限制 44

清单3.10 使用Thread Local确保线程封闭性 45

清单3.11 构造于底层可变对象之上的不可变类 47

清单3.12 在不可变的容器中缓存数字和它的因数 49

清单3.13 使用到不可变容器对象的volatile类型引用,缓存最新的结果 50

清单3.14 在没有适当的同步的情况下就发布对象(不要这样做) 50

清单3.15 如果Holder没有被正确发布,它将处于失败的风险中 51

清单4.1 使用Java监视器模式的简单线程安全计数器 56

清单4.2 使用限制确保线程安全 59

清单4.3 私有锁保护状态 61

清单4.4 基于监视器的机动车追踪器实现 63

清单4.5 类似于java.awt.Point的可变Point 64

清单4.6 DelegatingVehicleTracker使用不可变的Point类 64

清单4.7 将线程安全委托到ConcurrentHashMap 65

清单4.8 返回location集的静态拷贝,而非“现场(live)”的 66

清单4.9 委托线程安全到多个底层的状态变量 66

清单4.10 NumberRange类没有完整地保护它的不变约束(不要这样做) 67

清单4.11 可变的线程安全Point类 69

清单4.12 安全发布底层状态的机动车追踪器 70

清单4.13 扩展的Vector包含一个“缺少即加入”方法 72

清单4.14 非线程安全的“缺少即加入”实现(不要这样做) 72

清单4.15 使用客户端加锁实现的“缺少即加入” 73

清单4.16 使用组合(composition)实现“缺少即加入” 74

清单5.1 操作Vector的复合操作可能导致混乱的结果 80

清单5.2 使用客户端加锁,对Vector进行复合操作 81

清单5.3 迭代中可能抛出的ArrayIndexOutOfBoundsException 81

清单5.4 使用客户端加锁进行迭代 82

清单5.5 用Iterator对List进行迭代 82

清单5.6 迭代隐藏在字符串的拼接中(不要这样做) 84

清单5.7 ConcurrentMap接口 87

清单5.8 桌面搜索应用程序中的生产者和消费者 91

清单5.9 开始桌面搜索 92

清单5.10 恢复中断状态,避免掩盖中断 94

清单5.11 在时序测试中,使用CountDownLatch来启动和停止线程 96

清单5.12 使用FutureTask预载稍后需要的数据 97

清单5.13 Throwable强制转换为RuntimeException 98

清单5.14 使用信号量来约束容器 100

清单5.15 在一个细胞的自动系统中用CyclicBarrier协调计算 102

清单5.16 尝试使用HashMap和同步来初始化缓存 103

清单5.17 用ConcurrentHashMap替换HashMap 105

清单5.18 用FutureTask记录包装器 106

清单5.19 Memoizer最终实现 108

清单5.20 使用Memoizer为因式分解的servlet缓存结果 109

清单6.1 顺序化的Web Server 114

清单6.2 Web Server为每个请求启动一个新的线程 115

清单6.3 Executor接口 117

清单6.4 使用线程池的Web server 118

清单6.5 为每个任务启动一个新线程的Executor 118

清单6.6 Executor在调用线程中同步地执行所有任务 119

清单6.7 ExecutorService中的生命周期方法 121

清单6.8 支持关闭操作的Web Server 122

清单6.9 Timer的混乱行为 124

清单6.10 顺序地渲染页面元素 125

清单6.11 Callable interface和Future interface 126

清单6.12 ThreadPoolExecutor中newTaskFor的默认实现 126

清单6.13 使用Future等待图像下载 128

清单6.14 ExecutorCompletionService使用的QueueingFuture类 129

清单6.15 使用CompletionService渲染可用的页面元素 130

清单6.16 在预定时间内获取广告信息 132

清单6.17 在预定时间内请求旅游报价 134

清单7.1 使用volatile域保存取消状态 137

清单7.2 生成素数的程序运行一秒钟 137

清单7.3 不可靠的取消把生产者置于阻塞的操作中(不要这样做) 139

清单7.4 线程的中断方法 139

清单7.5 通过使用中断进行取消 141

清单7.6 向调用者传递InterruptedException 143

清单7.7 不可取消的任务在退出前保存中断 144

清单7.8 在外部线程中安排中断(不要这样做) 145

清单7.9 在一个专门的线程中中断任务 146

清单7.10 通过Future来取消任务 147

清单7.11 在Thread中,通过覆写interrupt来封装非标准取消 149

清单7.12 用newTaskFor封装任务中非标准取消 151

清单7.13 不支持关闭的生产者-消费者日志服务 152

清单7.14 向日志服务添加不可靠的关闭支持 153

清单7.15 向LogWriter添加可靠的取消 154

清单7.16 使用ExecutorService的日志服务 155

清单7.17 使用致命药丸来关闭 156

清单7.18 IndexingService的生产者线程 157

清单7.19 IndexingService的消费者线程 157

清单7.20 使用私有Executor,将它的寿命限定于一次方法调用中 158

清单7.21 关闭之后,ExecutorService获取被取消的任务 159

清单7.22 使用TrackingExecutorService为后续执行来保存未完成的任务 160

清单7.23 典型线程池的工作者线程的构建 162

清单7.24 UncaughtExceptionHandler接口 163

清单7.25 UncaughtExceptionHandler将异常写入日志 163

清单7.26 注册关闭钩子来停止日志服务 165

清单8.1 在单线程化的Executor中死锁的任务(不要这样做) 169

清单8.2 ThreadPoolExecutor通用的构造函数 172

清单8.3 创建一个可变长的线程池,使用受限队列和“调用者运行”饱和策略。 175

清单8.4 使用Semaphore来遏制任务的提交 176

清单8.5 ThreadFactory接口 176

清单8.6 定制的线程工厂 177

清单8.7 自定义的线程基类 178

清单8.8 修改一个标准工厂方法创建的Executor 179

清单8.9 扩展线程池以提供日志和计时功能 180

清单8.10 把顺序执行转换为并行执行 181

清单8.11 把顺序递归转换为并行递归 182

清单8.12 等待并行运算的结果 182

清单8.13 类似于“搬箱子”谜题的抽象 183

清单8.14 谜题解决者框架的链节点 184

清单8.15 顺序化的谜题解决者 185

清单8.16 并发版的谜题解决者 186

清单8.17 ConcurrentPuzzleSolver使用可携带结果的闭锁 187

清单8.18 能够感知任务不存在的解决者 188

清单9.1 使用Executor实现的SwingUtilities 193

清单9.2 构建于SwingUtilities之上的Executor 194

清单9.3 简单的事件监听器 194

清单9.4 将耗时任务绑定到可视化组件 196

清单9.5 提供用户反馈的耗时任务 196

清单9.6 取消耗时任务 197

清单9.7 支持取消、完成和进度通知的后台任务类 199

清单9.8 在BackgroundTask中启动一个耗时的、可取消的任务 200

清单10.1 简单的锁顺序死锁(不要这样做) 207

清单10.2 动态加锁顺序产生的死锁(不要这样做) 208

清单10.3 制定锁的顺序来避免死锁 209

清单10.4 开始一个循环,它在典型条件下制定死锁 210

清单10.5 协作对象问的锁顺序死锁(不要这样做) 212

清单10.6 使用开放调用来避免协作对象之间的死锁 214

清单10.7 发生死锁后线程转储的部分信息 217

清单11.1 串行访问任务队列 227

清单11.2 徒劳的同步(不要这样做) 230

清单11.3 锁省略的候选程序 231

清单11.4 持有锁超过必要的时间 233

清单11.5 减少锁持续的时间 234

清单11.6 应当分拆锁的候选程序 236

清单11.7 使用分拆的锁重构ServerStatus 236

清单11.8 基于哈希的map中使用分离锁 238

清单12.1 利用Semaphore实现的有限缓存 249

清单12.2 BoundedBuffer的基本单元测试 250

清单12.3 测试阻塞与响应中断 252

清单12.4 适用于测试的中等品质的随机数生成器 253

清单12.5 BoundedBuffer的生产者-消费者测试程序 255

清单12.6 PutTakeTest中的生产者和消费者类 256

清单12.7 测试资源泄漏 258

清单12.8 用于测试ThreadPoolExecutor的线程工厂 258

清单12.9 验证线程池扩展的测试方法 259

清单12.10 使用Thread.yield产生更多的交替操作 260

清单12.11 基于关卡的计时器 261

清单12.12 使用基于关卡的计时器进行测试 262

清单12.13 TimedPutTakeTest的驱动程序 262

清单13.1 Lock接口 277

清单13.2 使用ReentrantLock保护对象状态 278

清单13.3 使用tryLock避免锁顺序死锁 280

清单13.4 具有预定时间的锁 281

清单13.5 可中断的锁获取请求 281

清单13.6 ReadWriteLock接口 286

清单13.7 用读写锁包装的Map 288

清单14.1 状态依赖的可阻塞行为的结构 292

清单14.2 有限缓存不同实现的基类 293

清单14.3 如果有限缓存不满足先验条件,会停滞不前 294

清单14.4 调用GrumpyBoundedBuffer的客户端逻辑 294

清单14.5 有限缓存使用了拙劣的阻塞 296

清单14.6 有限缓存使用条件队列 298

清单14.7 状态依赖方法的规范式 301

清单14.8 在BoundedBuffer.put中使用“依据条件通知” 304

清单14.9 使用wait和notifyAll实现可重关闭的阀门 305

清单14.10 Conditon接口 307

清单14.11 有限缓存使用显式的条件变量 309

清单14.12 使用lock实现的计数信号量 310

清单14.13 AQS中获取和释放操作的规范式 312

清单14.14 二元闭锁使用AbstractQueuedSynchronizer 313

清单14.15 非公平的ReentrantLock中tryAcquire的实现 315

清单14.16 Semaphore的tryAcquireShared和tryAcquireShared方法 316

清单15.1 模拟CAS操作 322

清单15.2 使用CAS实现的非阻塞计数器 323

清单15.3 使用CAS避免多元的不变约束 326

清单15.4 使用ReentrantLock实现随机数字生成器 327

清单15.5 使用AtomicInteger实现随机数字生成器 327

清单15.6 使用Treiber算法(Treiber,1986)的非阻塞栈 331

清单15.7 Michael-Scott非阻塞队列算法中的插入(Michael与Scott,1996) 334

清单15.8 在ConcurrentLinkedQueue中使用原子化的域更新器 335

清单16.1 没有充分同步的程序可以产生令人惊讶的结果(不要这样做) 340

清单16.2 FutureTask的内部类示范了如何“驾驭”同步 343

清单16.3 不安全的惰性初始化(不要这样做) 345

清单16.4 线程安全的惰性初始化 347

清单16.5 主动初始化 347

清单16.6 惰性初始化holder类技巧 348

清单16.7 检查锁反模式(不要这样做) 349

清单16.8 不可变对象的初始化安全性 350