写作本书时,出于桌面系统的迫切需求,多核处理器正在变得越来越便宜。与此不协调的是,很多开发团队还没有注意到,在他们的项目中,出现了越来越多的关于线程的错误报告。在NetBeans开发者站点上最近的一次通告中,一位核心维护者注意到,为了修复某个类的一个线程相关的问题,已经被打了14次补丁。Dion Almaer,前TheServerSide的编辑(经过一次痛苦的调试过程,最终发现是一个线程的Bug之后),最近在Blog上写道,大多数Java程序都充斥着并发Bug,它们仅仅是“碰巧”可以工作。
的确,由于并发性的Bug不会以可预见的方式自己“蹦”出来,因此多线程程序的开发、测试和调试都会变得极端困难。Bug浮出水面的时刻,通常可能是最坏的时候——对应于生产环境,就是指在高负载的时候。
使用Java开发并发程序所要面对的挑战之一,是要面对平台提供的各种并发特性之间的不匹配,还有就是程序员在他们的程序中需要如何思考并发性。语言提供了一些低层机制,比如同步和条件等待,但是这些机制在实现应用级的协议与策略时才是必须的。不顾这些策略的约束,很容易创建出一个程序,它在编译和运行时看上去一切正常,不过却存在隐患。很多并发方面相当不错的书都没能达到预期的目标,它们过分关注于低层的机制和API,而不是设计层面的策略和模式。
Java 5.0是在使用Java开发并发应用程序的进程中,迈出的巨大一步。它提供了新的高层组件以及更多的低层机制,这些将使得一名新手更容易像专家那样去构建并发应用程序。本书的作者都是JCP专家组的主要成员,正是这个专家组创建了这些新工具;除了去描述新工具的行为和特性,我们还向您展示了它们低层的设计模式,预期的使用场景以及将它们纳入平台核心库的动机。
我们的目标是给读者一些设计法则和理念模型,让读者在使用Java构建正确、高效的并发类和应用程序时,变得更容易——更有趣。
我们希望你在阅读《Java并发编程实践》的过程中能够获得愉悦感。
Brian Goetz
2006年3月于Williston, VT
如何使用本书
Java低层机制与设计层必要的策略之间存在着抽象的不匹配。为了解决这个问题,我们呈现了一个经过简化的规则集,用来编写并发程序。专家们看到这些规则会说:“嗨,这可不是完整的规则,类C即使破坏了规则R,它仍然可以是线程安全的。”尽管打破我们的规则,也可能写出正确的并发程序,不过这样做需要对Java存储模型的低层细节有着深入的理解。我们的愿望是:开发者不用熟悉这些细节,就有能力编写正确的并发程序。只要坚持遵守我们简单的规则,就能编写出正确的、可维护的并发程序。
我们假设读者已经具备了对Java基本并发机制的一些了解。《Java并发编程实践》不是并发的入门指南——关于这个,可以参看任何正统的介绍性的大部头书籍,比如《Java编程语言》(Arnold et al., 2005)。本书也不是关于并发的百科全书似的参考手册——关于这个,可以参看《Java并发编程(Lea, 2000)》。对本书更恰当的描述是,它提供了实际的设计规则,可以协助开发者,他们正在处于创建安全的、高效的并发类这一艰难的过程中。在适当的地方,我们穿插引用了下列图书的章节:《The Java Programming Language》、《Concurrent Programming in Java》、《The Java Language Specification (Gosling et al., 2005)》以及《Effective Java(Bloch, 2001)》,并使用[JPL n.m]、[CPJ n.m]、[JLS n.m]和[EJ Item n]来表示它们。
结束 “介绍”(第1章)之后,本书分为4部分:
基础。第一部分(第2~5章)关注于同步和线程安全的基本概念,以及如何使用类库提供的构建块组合线程安全类。110页上,有一个“并发诀窍清单”总结了出现在第一部分中最重要的规则。
第2章(线程安全性)与第3章(共享对象)构成了全书的基础。几乎所有用来避免并发危险、创建线程安全类以及验证线程安全的规则都包括在这里。轻“理论”,重“实践”的读者可能会禁不住诱惑跳过这部分,而直接进入第二部分,但是在开始编写任何并发代码之前,一定要确保回过头来阅读这两章!第4章所涵盖的技术,用于把线程安全类组合到更大的线程安全类中。第5章(构建块)涵盖了平台核心库提供的并发构建块——线程安全的容器和同步工具(synchronizer)。
构建并发应用程序。第二部分(第6~9章)描述了如何利用线程提高并发应用程序的吞吐量或响应性。第6章(任务执行)讲述如何识别可并行执行的任务,并在任务执行框架内部执行它们。第7章讲到的技术可以让任务和线程在正常终止之前妥善地终止;区分并发应用程序是健壮的,还是仅仅可以将就工作的,有众多的因素,“程序如何处理取消与关闭”就是其中之一。第8章(应用线程池)关注了一些任务执行框架中更为高级的特性。
第9章(GUI应用程序)关注了用来提高单线程化子系统响应性的技术。
活跃度、性能和测试。第三部分(第10~12章)涉及并发程序自身。要确保并发程序执行了你所希望它做的事情,而且性能是可以接受的。第10章(避免活跃度危险)描述了如何避免活跃度失败,活跃度失败会阻止程序继续向前执行。第11章(性能和可伸缩性)涵盖的技术用来提高并发代码的性能和可伸缩性。第12章(测试并发程序)涵盖的技术用来测试并发代码的正确性和性能。
高级主题。第四部分(第13~16章)涵盖的主题可能只会引起资深程序员的兴趣:它们是显式锁、原子变量、非阻塞算法和开发自定义的synchronizer。
代码示例
尽管书中很多的通用概念适用于Java 5.0之前版本,甚至是非Java环境,不过大多数示例代码(以及关于Java存储模型的每一句话)都假定是以Java 5.0或更新的JDK为基础的。有些代码示例还会用到Java 6中添加到类库中的特性。
代码示例已经被裁减,以降低它们的尺寸和突出相关的部分。完整版本的代码示例、辅助示例和勘误表,可以从本书的网站http://www.javaconcurrencyinpractice.com上获得。
代码示例分为三类:“好”示例,“一般”示例和“坏”示例。“好”示例阐释的技术应该被效仿。“坏”示例阐释的技术绝对不应该被效仿,而且还会用一个“Mr. Yuk”1的图标清楚地表明这是“有害”的代码(参见清单1)。“一般”示例阐释的技术不一定是错的,但却是是脆弱的、有风险的或者执行效果差的,而且会用一个“Mr. CouldBeHappier”图标标识出来,如同清单2。
清单1 糟糕的清单排序方法(不要这样做)
public <T
extends Comparable<? super T>> void sort(List<T> list) {
// 永远不要返回错误的答案
System.exit(0);
}
有些读者会质疑“坏”示例在本书中的角色;毕竟,一本书应该展现如何做正确的事,而不是错误的事。“坏”示例有两个目的。它们揭示了常见的缺陷,更重要的是它们示范了如何分析程序的线程安全性——完成此事的最佳办法就是观察威胁线程安全的各种方式。
清单2 缺少优化的清单排序方法
public <T extends Comparable<? super T>> void sort(List<T> list) {
for (int i=0; i<1000000; i++)
doNothing();
Collections.sort(list);
}
致谢
java.util.concurrent包的开发过程催生了本书。这个包是由Java Community Process JSR 166创建的,后被加入到Java 5.0中。还有很多人为JSR 166作出过贡献;我们尤其要感谢Martin Buchholz,他完成了所有把代码植入JDK的相关工作;还要感谢concurrency-interest邮件清单的所有读者,他们为API的草案提供了他们的建议和反馈。
本书能够大幅度地完善,得益于大量的建议和帮助,这些帮助来自多方面的人员。我们要感谢Dion Almaer,Tracy Bialik,Cindy Bloch,Martin Buchholz,Paul Christmann,Cliff Click,Stuart Halloway,David Hovemeyer,Jason Hunter,Michael Hunter,Jeremy Hylton,Heinz Kabutz,Robert Kuhar,Ramnivas Laddad,Jared Levy,Nicole Lewis,Victor Luchangco,Jeremy Manson,Paul Martin,Berna Massingill,Michael Maurer,Ted Neward,Kirk Pepperdine,Bill Pugh,Sam Pullara,Russ Rufer,Bill Scherer,Jeffrey Siegal,Bruce Tate,Gil Tene,Paul Tyma,以及硅谷模式小组的成员,他们通过很多饶有趣味的技术交流,提供了指南,提出了建议,这些对本书能够做到更好颇有帮助。
我们格外感激Cliff Biffle,Barry Hayes,Dawid Kurzyniec,Angelika Langer,Doron Rajwan和Bill Venners,他们审阅了全部手稿,还关注了令人烦恼的细节,寻找代码示例中的bug,并且提出了大量令本书得以改进的建议。
我们感谢Katrina Avery,他出色地完成了copy-editing的工作;Rosemary Simpson在极端的时间压力下,还制作了索引。我们感谢Ami Dewar绘制的插图。
感谢Addison-Wesley的全体组员,他们让这本书得以问世。Ann Sellers让项目得以运行;Greg Doench 让项目的进度有条不紊;Elizabeth Ryan一直领导着本书写作的进程。
我们还想要感谢成千上万的软件工程师,他们开发了编写本书所用到的软件,间接地为本书作出了贡献。这些软件包括TEX,LATEX,Adobe Acrobat,pic,grap,Adobe Illustrator,Perl,Apache Ant,IntelliJ IDEA,GNU emacs,Subversion,TortoiseSVN,当然,还有Java平台与类库。






