Java 平台提供了一套广泛而功能强大的 API、工具和技术。其中,内建支持线程是它的一个强大的功能。这一功能为使用 Java 编程语言的程序员提供了并发编程这一诱人但同时也非常具有挑战性的选择。本专题汇集了与 Java 多线程与并发编程相关的文章和教程,帮助读者理解 Java 并发编程的模式及其利弊,向读者展示了如何更精确地使用 Java 平台的线程模型。

Java 线程基础

Java 程序中的多线程
由于在语言级提供了线程支持,在 Java 语言中使用多线程要远比在 C 或 C++ 中来得简单。本文通过简单的程序示例展现了在 Java 程序中线程编程的简单性。在学习完本文后,用户应该能够编写简单的多线程程序。

编写多线程的 Java 应用程序
Java Thread API 允许程序员编写具有多处理机制优点的应用程序,在后台处理任务的同时保持用户所需的交互感。本文介绍了 Java Thread API,并概述多线程可能引起的问题以及常见问题的解决方案。

如果我是国王:关于解决 Java 编程语言线程问题的建议
Allen Holub 指出,Java 编程语言的线程模型可能是此语言中最薄弱的部分。它完全不适合实际复杂程序的要求,而且也完全不是面向对象的。本文建议对 Java 语言进行重大修改和补充,以解决这些问题。

Java 多线程开发

Java 多线程在交易中间件测试中的应用
在交易中间件的性能测试中,经常需要模拟多个用户并行的测试场景,Java 的多线程编程能有效地模拟这些场景,使测试方法更灵活。本文以一个交易中间件的测试为例,介绍了如何使用 Java 多线程编程来模拟多个用户的随机或有规律的行为,让您在进行多用户并发测试时有一种新的实现选择。

构建 Java 并发模型框架
线程间同步、数据一致性等烦琐的问题需要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误。另外,应用逻辑和线程逻辑纠缠在一起,会导致程序的逻辑结构混乱,难以复用和维护。本文试图给出一个解决这个问题的方案,通过构建一个并发模型框架,使得开发多线程的应用变得容易。

使您轻松地进行多线程应用程序编程
生产者/消费者方案是多线程应用程序开发中最常用的构造之一 — 因此困难也在于此。因为在一个应用程序中可以多次重复生产者/消费者行为,其代码也可以如此。本文创建了 Consumer 类,该类通过在一些多线程应用程序中促进代码重用以及简化代码调试和维护来解决这个问题 。

使用 Java 建立稳定的多线程服务器
本文详细的介绍了使用 Java 语言建立一套多线程服务器的过程,该服务器使用对象传递消息,在线程中使用队列机制,使服务器的性能大大提高了。这套服务器可以被用于各种 C/S 或 B/S 结构的应用程序中。

线程池的介绍及简单实现
服务器程序利用线程技术响应客户请求已经司空见惯,可能您认为这样做效率已经很高,但您有没有想过优化一下使用线程的方法。本文将向您介绍服务器程序如何利用线程池来优化性能并提供一个简单的线程池实现。

Java 实时多任务调度过程中的安全监控设计
在一系列关联的多任务的实时环境中,如果有一个任务发生失败,可能导致所有任务产生连锁反应,从而造成调度失控的局面。特别是对于核心控制设备尤其重要,为了解决这个问题,必须对每个任务进行实时监控。

线程安全与同步

不要重新分配被锁定对象的对象引用
当一个实例在同步代码中被锁定,对此对象和其引用的修改会是咋样呢?对一个对象的同步操作只是锁定了该对象。您需要注意不要重新分配被锁定对象的引用。

以一个固定、全局次序获取多个锁
当两个或多个线程在互相等待时被阻塞就发生了死锁。死锁是在多线程代码中最难解决的问题。要解决它,就必须以一个固定、全局次序获取多个锁。

Java 单例对象同步问题探讨
本文将探讨在多线程环境下,使用单例对象作配置信息管理时可能会带来的几个同步问题,并针对每个问题给出可选的解决办法。

Java 理论与实践: 描绘线程安全性
7月份我们的并发专家 Brian Goetz 将 Hashtable 和 Vector 类描述为“有条件线程安全的”。一个类难道不是线程安全就是线程不安全的吗?不幸的是,线程安全并不是一个非真即假的命题,它的定义出人意料的困难。但是,正如Brian 在本月的 Java 理论与实践中解释的,尽量在 Javadoc 中对类的线程安全性进行归类是非常重要的。

编写高效的线程安全(thread-safe)类
在语言级别支持对象的锁定和线程内信号机制使得编写线程安全的类变得简单。在这里,通过简单的程序示例描述了在 Java 中强大和独具一格的线程安全和高效类的开发。

轻松使用线程
与许多其它的编程语言不同,Java 语言规范包括对线程和并发的明确支持。语言本身支持并发,这使得指定和管理共享数据的约束以及跨线程操作的计时变得更简单,但是这没有使得并发编程的复杂性更易于理解。这个三部分的系列文章的目的在于帮助程序员理解用 Java 语言进行多线程编程的一些主要问题,特别是线程安全对 Java 程序性能的影响。

  • 第 1 部分,同步不是敌人
    在本系列的第 1 部分,我们将讨论什么时候需要同步,而同步的代价到底有多大?

  • 第 2 部分,减少争用
    严重的争用将严重损害应用程序的可伸缩性 — 随着负载的增加,存在严重争用同步的应用程序的性能将显著降低。本文将探讨能够减少争用的几种技术,以提高您程序的可伸缩性。

  • 第 3 部分,不共享有时是最好的
    ThreadLocal 类是悄悄地出现在 Java 平台版本 1.2 中的。虽然 ThreadLocal 极少受到关注,但对简化线程安全并发程序的开发来说,它却是很方便的。本文研究了 ThreadLocal 并提供了一些使用技巧。

适用于 Java 程序员的 CSP
在这篇由三部分组成的系列文章中,介绍了一个理论,该理论承认了并发编程的复杂性,并且没有试图隐藏这种复杂性,或者使它不那么难于学习和应用。通信顺序进程(Communicating Sequential Processes —— CSP) 是一个精确的并发数学理论,可以用来构建多线程应用程序,确保构建的程序中不出现并发的常见问题,而且更重要的是,这一点 能够得到证实。

  • 第 1 部分,在 Java 平台上进行多线程编程的缺陷
    本文先从 Java 平台的并发编程技术概述开始,接着提供了多线程应用程序开发缺陷的深入概述,这些缺陷包括:竞争冒险、死锁、活动锁和资源耗尽等。

  • 第 2 部分,用 JCSP 进行并发编程
    本文将介绍如何使用基于 Java 的 JCSP 库来编写能够确保没有并发问题(例如争用风险、 死锁、活动锁、资源耗尽)的 Java 应用程序。

  • 第 3 部分,JCSP 的高级主题
    本文通过介绍 JCSP 开发高级主题,结束了由三部分组成的介绍适用于 Java 开发人员的 CSP 的系列文章,介绍的内容包括:JCSP 与 AOP 的相似性、JCSP 与 java.util.concurrent 的比较,以及用 JCSP 进行高级同步。

实现一个不受约束的不变性模型
不变对象对于编写线程安全的软件来说非常有帮助。在 Java 语言中,保证不变性的主要机制是使用 final 字段。但 final 字段必须在构造函数中设置,而在一些情况中,这一要求未免太过局限。本文将介绍一种有效的实现方式,使用标准缓存字段来实现一个略微随意的不变性模型,该字段的值无需同步也能安全访问。

实时 Java: 线程化和同步
本文是关于实时 Java 系列文章(共 5 部分)的第三篇,考察了 Java 实时规范(RTSJ)的实现必须支持的线程化和同步问题。您还将了解开发和部署实时应用程序时必须牢记的一些有关这两方面的基本考虑。

IBM 的 Java 诊断: 使用面向 Java 的 Lock Analyzer 诊断同步和锁问题
锁争用会降低应用程序性能,该工具会突出显示发生锁争用的线程。 开发人员可以使用该信息修改其应用程序以减少锁争用,从而提高性能。本文介绍了面向 Java 的 IBM 锁分析器,介绍了其构建的基础架构并针对该工具的未来发展方向进行了思考。

并发控制

实现 Java 多线程并发控制框架
Java 多线程是提高程序效能的利器,本文并不是告诉您如何编写多线程 Java 程序,而着重于多线程的并发控制以及如何描述线程执行的过程。当您需要完全掌控 Java 多线程执行的过程时,本文将会对您有所帮助。

多线程、多平台环境中的跟踪
大多数 Java 程序员都使用某种跟踪系统来跟踪开发中的代码的潜在错误和问题。然而,多线程和多平台环境可能产生大量莫名其妙的跟踪数据。本文提供了一些技巧,帮助您理解复杂应用程序中产生的跟踪数据。

使用 ConTest 进行多线程单元测试
众所周知并行程序设计易于产生 bug。更为严重的是,往往在开发过程的晚期当这些并行 bug 引起严重的损害时才能发现它们并且难于调试它们。即使彻底地对它们进行了调试,常规的单元测试实践也很可能遗漏并行 bug。本文解释了为什么并行 bug 如此难于捕获并且介绍了 IBM Research 的一种新的解决方案。

非阻塞套接字(NIO)

NIO 入门
在本教程中,我们将讨论 NIO 库的几乎所有方面,从高级的概念性内容到底层的编程细节。除了学习诸如缓冲区和通道这样的关键 I/O 元素外,您还有机会看到在更新后的库中标准 I/O 是如何工作的。您还会了解只能通过 NIO 来完成的工作,如异步 I/O 和直接缓冲区。

实现非阻塞套接字的一种简单方法
尽管 SSL 阻塞操作 — 当读写数据的时候套接字的访问被阻塞 — 与对应的非阻塞方式相比提供了更好的 I/O 错误通知,但是非阻塞操作允许调用的线程继续运行。本文中,作者同时就客户端和服务器端描述了如何使用 Java Secure Socket Extensions (JSSE) 和 Java NIO (新 I/O)库创建非阻塞的安全连接,并且介绍了创建非阻塞套接字的传统方法,以及使用 JSSE 和 NIO 的一种可选的(必需的)方法。

基于事件的 NIO 多线程服务器
JDK 1.4 提供的非阻塞 I/O(NIO)有效解决了多线程服务器存在的线程开销问题,但在使用上略显得复杂一些。许多基于 NIO 的多线程服务器程序往往直接基于选择器(Selector)的 Reactor 模式实现。这种简单的事件机制对于较复杂的服务器应用,显然缺乏扩展性和可维护性, 而且缺乏直观清晰的结构层次。本文将通过一个基于事件回调的 NIO 多线程服务器的设计,试图提供一个简洁、直观、易于扩展的 NIO 多线程服务器模型。

Java 5 中的并发

驯服 Tiger: 并发集合
Doug Lea 最初编写的 util.concurrent 包变成了 JSR-166 ,然后又变成了 J2SE 平台的 Tiger 版本。这个新库提供的是并发程序中通常需要的一组实用程序。如果对于优化对集合的多线程访问有兴趣,那么您就找对地方了。

JDK 5.0 中的并发
本教程将介绍 JDK 5.0 提供的用于并发的新实用程序类,并通过与现有并发原语(synchronized、wait() 和 notify())相比较,说明这些类如何提高了可伸缩性。

Java5 多线程实践
Java 5 增加了新的类库并发集 java.util.concurrent,该类库为并发程序提供了丰富的 API,使多线程编程在 Java 5 中更加容易,灵活。本文通过一个网络服务器模型,来实践 Java 5 的多线程编程,该模型中使用了 Java 5 中的线程池、阻塞队列、可重入锁等,还实践了 Callable、 Future 等接口,并使用了 Java 5 的另外一个新特性泛型。

Java 理论与实践
下列文章来自并发行专家 Brian Goetz 的“Java 理论与实践”系列专栏,讨论了 JDK 5 中并发编程。

  • 并发集合类
    DougLea 的 util.concurrent 包除了包含许多其他有用的并发构造块之外,还包含了一些主要集合类型 List 和 Map 的高性能的、线程安全的实现。本文向您展示了用 ConcurrentHashMap 替换 Hashtable 或 synchronizedMap ,将有多少并发程序获益。

  • 构建一个更好的 HashMap
    ConcurrentHashMap 是 Doug Lea 的 util.concurrent 包的一部分,它提供比 Hashtable 或者 synchronizedMap 更高程度的并发性。而且,对于大多数成功的 get() 操作它会设法避免完全锁定,其结果就是使得并发应用程序有着非常好的吞吐量。本文仔细分析了 ConcurrentHashMap 的代码,并探讨 Doug Lea 是如何在不损失线程安全的情况下取得这么骄人成绩的。

  • JDK 5.0 中更灵活、更具可伸缩性的锁定机制
    JDK 5.0 为开发人员开发高性能的并发应用程序提供了一些很有效的新选择。例如,java.util.concurrent.lock 中的类 ReentrantLock 被作为 Java 语言中 synchronized 功能的替代,它具有相同的内存语义、相同的锁定,但在争用条件下却有更好的性能,此外,它还有 synchronized 没有提供的其他特性。这是否意味着我们应当忘记 synchronized,转而只用 ReentrantLock 呢?并发性专家 Brian Goetz 刚从他的夏季休假中返回,他将为我们提供答案。

  • 流行的原子
    在 JDK 5.0 之前,如果不使用本机代码,就不能用 Java 语言编写无等待、无锁定的算法。在 java.util.concurrent 中添加原子变量类之后,这种情况发生了变化。请跟随本文一起,了解这些新类如何使用 Java 语言开发高度可伸缩的无阻塞算法。您可以在本文的论坛中与作者或其他读者共享您对本文的看法。

  • 非阻塞算法简介
    Java 5.0 第一次让使用 Java 语言开发非阻塞算法成为可能,java.util.concurrent 包充分地利用了这个功能。非阻塞算法属于并发算法,它们可以安全地派生它们的线程,不通过锁定派生,而是通过低级的原子性的硬件原生形式 ―― 例如比较和交换。非阻塞算法的设计与实现极为困难,但是它们能够提供更好的吞吐率,对生存问题(例如死锁和优先级反转)也能提供更好的防御。在这期的 Java 理论与实践 中,并发性大师 Brian Goetz 演示了几种比较简单的非阻塞算法的工作方式。

  • 处理 InterruptedException
    Java 语言的很多方法,例如 Thread.sleep() 和 Object.wait(),都可以抛出 InterruptedException。这个异常是不能忽略的,因为它是一个检查异常(checked exception)。但是应该如何处理它呢?在本月的 “Java 理论与实践” 中,并发专家 Brian Goetz 将解释 InterruptedException 的含义,为什么抛出 InterruptedException,以及在捕捉到该异常时应该怎么做。

  • 正确使用 Volatile 变量
    Java 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。在这期的 Java 理论与实践中,Brian Goetz 将介绍几种正确使用 volatile 变量的模式,并针对其适用性限制提出一些建议。

使用泛型和并发改善集合
Java Collections Framework 是 Java 平台的一个重要部分。桌面和企业应用程序通常都使用该框架来聚集集合项。本文将向您展示如何使用集合,同时利用 Java SE 6 中对该框架的增强。通过使用泛型和并发功能使您的应用程序具有更好的维护性和可伸缩性,您可以实现比 HashMap 或 TreeSet 更丰富的功能。

JDK 7 中的 Fork/Join 模式

JDK 7 中的 Fork/Join 模式
随着多核时代的来临,软件开发人员不得不开始关注并行编程领域。而 JDK 7 中将会加入的 Fork/Join 模式是处理并行编程的一个经典的方法。虽然不能解决所有的问题,但是在它的适用范围之内,能够轻松的利用多个 CPU 提供的计算资源来协作完成一个复杂的计算任务。通过利用 Fork/Join 模式,我们能够更加顺畅的过渡到多核的时代。本文将介绍使用 JDK 7 中 Fork/Join 模式的方法和其他相关改进。阅读本文之后,读者将能够独立地在软件开发中使用 Fork/Join 模式来改进程序的性能。

Java 理论与实践: 应用 fork-join 框架
Java 7 的 java.util.concurrent 包的新增功能之一是一个 fork-join 风格的并行分解框架。fork-join 概念提供了一种分解多个算法的自然机制,可以有效地应用硬件并行性。

Java 理论与实践: 应用 fork-join 框架,第 2 部分
在第 1 部分中,Brian Goetz 演示了 fork-join 如何为众多的算法提供一种自然的分解机制,以有效地利用硬件的并行性。在本文中,他将介绍 ParallelArray 类,这个类简化了内存中数据结构上的并行排序和搜索操作。

相关书评

不仅仅是另一本并发性图书
如果以前没有购买 Java Concurrency in Practice(Goetz 等,Addison-Wesley,2006 年),那么现在该购买了。经验丰富的 Java 开发人员(和流行书作者)Sing Li 介绍了为什么即使并发性还没进入您的日常开发,也应当阅读这本重要的图书。该书由 developerWorks 的长期作者和并发性专家 Goetz 执笔。