如今,计算机系统(以及其他相关系统,如平板电脑或智能手机)允许您同时执行多项任务。这是可能的,因为它们拥有同时控制多个任务的并发操作系统。如果使用您最喜欢的编程语言的并发 API,您还可以让一个应用程序执行多个任务(读取文件、显示消息或通过网络读取数据)。Java 包含一个非常强大的并发 API,它允许您轻松实现任何类型的并发应用程序。此 API 增加了每个版本中为程序员提供的功能。现在,在 Java8 中,它包含了流 API 和新的方法和类,以方便并发应用程序的实现。本书涵盖了 Java 并发 API 的最重要元素,向您展示了如何在实际应用程序中使用它们。这些要素如下:
如今,计算机系统(以及其他相关系统,如平板电脑或智能手机)允许您同时执行多项任务。这是可能的,因为它们拥有同时控制多个任务的并发操作系统。如果使用您最喜欢的编程语言的并发 API,您还可以让一个应用执行多个任务(读取文件、显示消息或通过网络读取数据)。Java 包含一个非常强大的并发 API,它允许您轻松实现任何类型的并发应用。此 API 增加了每个版本中为程序员提供的功能。现在,在 Java8 中,它包含了流 API 和新的方法和类,以方便并发应用的实现。本书涵盖了 Java 并发 API 的最重要元素,向您展示了如何在实际应用中使用它们。这些要素如下:
[第一章](01.html#DB7S2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 1. The First Step – Concurrency Design Principles")*第一步——并发设计原则*将教您并发应用程序的设计原则。他们还将学习并发应用程序可能存在的问题,以及设计并发应用程序的方法,然后学习一些设计模式、技巧和技巧。
[第一章](01.html#DB7S2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 1. The First Step – Concurrency Design Principles")*第一步——并发设计原则*将教您并发应用的设计原则。他们还将学习并发应用可能存在的问题,以及设计并发应用的方法,然后学习一些设计模式、技巧和技巧。
[第三章](03.html#QMFO1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 3. Getting the Maximum from Executors")*从执行者*获取最大值,将教您执行者的一些高级特性,包括取消和调度任务,以在延迟后或每隔一定时间执行任务。您将实现一个高级客户机/服务器应用程序和一个新闻阅读器。
[第三章](03.html#QMFO1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 3. Getting the Maximum from Executors")*从执行者*获取最大值,将教您执行者的一些高级特性,包括取消和调度任务,以在延迟后或每隔一定时间执行任务。您将实现一个高级客户机/服务器应用和一个新闻阅读器。
[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")*从任务中获取数据–可调用和未来接口*将教会您如何在执行者中处理使用可调用和未来接口返回结果的任务。您将实现一个最佳匹配算法和一个应用程序来构建反向索引。
[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")*从任务中获取数据–可调用和未来接口*将教会您如何在执行者中处理使用可调用和未来接口返回结果的任务。您将实现一个最佳匹配算法和一个应用来构建反向索引。
[第 5 章](05.html#1394Q1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 5. Running Tasks Divided into Phases – The Phaser Class")*运行分阶段的任务–Phaser 类*将教您如何使用 Phaser 类并行执行可分阶段的任务。您将实现关键字提取算法和遗传算法。
[第 6 章](06.html#173722-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 6. Optimizing Divide and Conquer Solutions – The Fork/Join Framework")*优化分治解决方案–Fork/Join 框架*将教您如何使用一种特殊类型的执行器,该执行器通过分治技术可以解决的问题进行优化:Fork/Join 框架及其偷功算法。您将实现 k-means 聚类算法、数据过滤算法和合并排序算法。
[第 7 章](07.html#1CQAE2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 7. Processing Massive Datasets with Parallel Streams – The Map and Reduce Model")*使用并行流处理海量数据集–映射和简化模型*将教您如何使用流处理大型数据集。在本章中,您将学习如何使用 stream API 和 streams 的更多功能实现映射和缩减应用程序。您将实现一个数字摘要算法和一个信息检索搜索工具。
[第 7 章](07.html#1CQAE2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 7. Processing Massive Datasets with Parallel Streams – The Map and Reduce Model")*使用并行流处理海量数据集–映射和简化模型*将教您如何使用流处理大型数据集。在本章中,您将学习如何使用 stream API 和 streams 的更多功能实现映射和缩减应用。您将实现一个数字摘要算法和一个信息检索搜索工具。
[第 8 章](08.html#1GKCM1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 8. Processing Massive Datasets with Parallel Streams – The Map and Collect Model")*处理具有并行流的海量数据集–映射和收集模型*,将教您如何使用流 API 的 Collect()方法将数据流可变地简化为不同的数据结构,包括收集器类中定义的预定义收集器。您将实现一个无索引搜索数据的工具、一个推荐系统和一个计算社交网络中两个人的常见联系人列表的算法。
[第 9 章](09.html#1LCVG2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 9. Diving into Concurrent Data Structures and Synchronization Utilities"),*深入探讨并发数据结构和同步实用程序,*将教您如何使用最重要的并发数据结构(可以在并发应用程序中使用的数据结构,而不会造成数据争用情况)以及 Java 并发 API 中包含的所有同步机制来组织任务的执行。
[第 9 章](09.html#1LCVG2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 9. Diving into Concurrent Data Structures and Synchronization Utilities"),*深入探讨并发数据结构和同步工具,*将教您如何使用最重要的并发数据结构(可以在并发应用中使用的数据结构,而不会造成数据争用情况)以及 Java 并发 API 中包含的所有同步机制来组织任务的执行。
[第 10 章](10.html#1O8H61-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 10. Integration of Fragments and Implementation of Alternatives")*片段集成和备选方案的实现*将教您如何使用共享内存或消息传递,使用并发应用程序片段自身的并发技术实现大型应用程序。您还将学习本书中示例的不同实现替代方案。
[第 10 章](10.html#1O8H61-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 10. Integration of Fragments and Implementation of Alternatives")*片段集成和备选方案的实现*将教您如何使用共享内存或消息传递,使用并发应用片段自身的并发技术实现大型应用。您还将学习本书中示例的不同实现替代方案。
[第 11 章](11.html#1S2JE2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 11. Testing and Monitoring Concurrent Applications")*测试和监控并发应用程序*教您如何获取一些 Java 并发 API 元素(线程、锁、执行器等)的状态信息。您还将学习如何使用 Java VisualVM 应用程序监视并发应用程序,以及如何使用多线程 DC 库和 Java Pathfinder 应用程序测试并发应用程序。
[第 11 章](11.html#1S2JE2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 11. Testing and Monitoring Concurrent Applications")*测试和监控并发应用*教您如何获取一些 Java 并发 API 元素(线程、锁、执行器等)的状态信息。您还将学习如何使用 Java VisualVM 应用监视并发应用,以及如何使用多线程 DC 库和 Java Pathfinder 应用测试并发应用。
# 这本书你需要什么
...
...
@@ -41,7 +41,7 @@
# 这本书是给谁的
如果您是一名 Java 开发人员,了解并发编程的基本原理,但希望获得 Java 并发 API 的专家知识,以开发利用计算机所有硬件资源的优化应用程序,那么本书适合您。
如果您是一名 Java 开发人员,了解并发编程的基本原理,但希望获得 Java 并发 API 的专家知识,以开发利用计算机所有硬件资源的优化应用,那么本书适合您。
在[第 3 章](03.html#QMFO1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 3. Getting the Maximum from Executors")、*从执行器获取最大值*、[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")、*从任务获取数据–可调用和未来接口*中,我们将介绍执行器的更高级方面。
**客户机/服务器模式**是一种软件架构,其中应用程序分为两部分:提供资源(数据、操作、打印机、存储等)的服务器部分和使用服务器提供的资源的客户机部分。传统上,这种体系结构用于企业界,但随着互联网的繁荣,它仍然是一个实际的话题。您可以将 web 应用程序视为客户机/服务器应用程序,其中服务器部分是在 web 服务器中执行的应用程序的后端部分,web navigator 执行应用程序的客户机部分。**SOA**(简称**面向服务架构**)是客户机/服务器架构的另一个示例,其中公开的 web 服务是服务器部分,使用它们的不同客户机是客户机部分。
**客户机/服务器模式**是一种软件架构,其中应用分为两部分:提供资源(数据、操作、打印机、存储等)的服务器部分和使用服务器提供的资源的客户机部分。传统上,这种体系结构用于企业界,但随着互联网的繁荣,它仍然是一个实际的话题。您可以将 web 应用视为客户机/服务器应用,其中服务器部分是在 web 服务器中执行的应用的后端部分,web navigator 执行应用的客户机部分。**SOA**(简称**面向服务架构**)是客户机/服务器架构的另一个示例,其中公开的 web 服务是服务器部分,使用它们的不同客户机是客户机部分。
在[第 9 章](09.html#1LCVG2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 9. Diving into Concurrent Data Structures and Synchronization Utilities")中*深入到并发数据结构和同步实用程序*中,我们将更详细地描述并发数据结构。
在[第 9 章](09.html#1LCVG2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 9. Diving into Concurrent Data Structures and Synchronization Utilities")中*深入到并发数据结构和同步工具*中,我们将更详细地描述并发数据结构。
# 总结
在简单的并发应用程序中,我们使用`Runnable`接口和`Thread`类执行并发任务。我们创建和管理线程并控制它们的执行。我们不能在大型并发应用程序中采用这种方法,因为它会给我们带来很多问题。对于这些情况,Java 并发 API 引入了 executor 框架。在本章中,我们介绍了构成该框架的基本特征和组件。首先是`Executor`接口,它定义了向执行者发送`Runnable`任务的基本方法。这个接口有一个子接口,`ExecutorService`接口,它包括发送给返回结果的执行者任务的方法(这些任务实现`Callable`接口,我们将在[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")中看到,*从任务获取数据–可调用和未来的接口*以及任务列表。
在简单的并发应用中,我们使用`Runnable`接口和`Thread`类执行并发任务。我们创建和管理线程并控制它们的执行。我们不能在大型并发应用中采用这种方法,因为它会给我们带来很多问题。对于这些情况,Java 并发 API 引入了 executor 框架。在本章中,我们介绍了构成该框架的基本特征和组件。首先是`Executor`接口,它定义了向执行者发送`Runnable`任务的基本方法。这个接口有一个子接口,`ExecutorService`接口,它包括发送给返回结果的执行者任务的方法(这些任务实现`Callable`接口,我们将在[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")中看到,*从任务获取数据–可调用和未来的接口*以及任务列表。
@@ -844,7 +844,7 @@ public class NewsTask implements Runnable {
}
```
在本例中,我们还实现了另一个线程来实现执行器和任务的初始化以及等待执行的最终完成。我们将这个类命名为`NewsSystem`。它有三个内部属性来存储 RSS 源文件的路径、存储新闻的缓冲区和控制执行结束的`CountDownLatch`对象。`CountDownLatch`类是一种同步机制,允许您让线程等待事件。我们将在[第 9 章](09.html#1LCVG2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 9. Diving into Concurrent Data Structures and Synchronization Utilities")中详细介绍此类的使用,*将深入探讨并发数据结构和同步实用程序*。我们有以下代码:
在本例中,我们还实现了另一个线程来实现执行器和任务的初始化以及等待执行的最终完成。我们将这个类命名为`NewsSystem`。它有三个内部属性来存储 RSS 源文件的路径、存储新闻的缓冲区和控制执行结束的`CountDownLatch`对象。`CountDownLatch`类是一种同步机制,允许您让线程等待事件。我们将在[第 9 章](09.html#1LCVG2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 9. Diving into Concurrent Data Structures and Synchronization Utilities")中详细介绍此类的使用,*将深入探讨并发数据结构和同步工具*。我们有以下代码:
并发 API 中最重要的元素是它为程序员提供的同步机制。**同步**是协调两个或多个任务以获得所需结果。当必须按预定义顺序执行两个或多个任务时,您可以同步它们的执行;当一次只有一个线程可以执行代码片段或修改内存块时,您可以同步对共享资源的访问。Java 8 并发 API 提供了许多同步机制,从基本的`synchronized`关键字或`Lock`接口及其实现,以保护关键部分到更高级的`CyclicBarrier`或`CountDownLatch`类,这些类允许您同步不同任务的执行顺序。在 Java7 中,并发 API 引入了`Phaser`类。此类提供了一个强大的机制(**移相器**来执行分阶段的任务。任务可以要求 Phaser 类等待所有其他参与者完成该阶段。在本章中,我们将介绍以下主题:
在[第 2 章](02.html#KVCC1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 2. Managing Lots of Threads – Executors")、*管理大量线程–执行器*、[第 3 章](03.html#QMFO1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 3. Getting the Maximum from Executors")、*从执行器获取最大值*、[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")、*从任务获取数据–可调用和未来接口*,您学习了如何使用执行器作为一种机制来提高执行大量并发任务的并发应用程序的性能。Java7 并发 API 通过 Fork/Join 框架引入了一种特殊的执行器。该框架旨在为那些可以使用分而治之设计范式解决的问题实现最佳并行解决方案。在本章中,我们将介绍以下主题:
在[第 2 章](02.html#KVCC1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 2. Managing Lots of Threads – Executors")、*管理大量线程–执行器*、[第 3 章](03.html#QMFO1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 3. Getting the Maximum from Executors")、*从执行器获取最大值*、[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")、*从任务获取数据–可调用和未来接口*,您学习了如何使用执行器作为一种机制来提高执行大量并发任务的并发应用的性能。Java7 并发 API 通过 Fork/Join 框架引入了一种特殊的执行器。该框架旨在为那些可以使用分治设计范式解决的问题实现最佳并行解决方案。在本章中,我们将介绍以下主题:
Java8 在 Fork/Join 框架中包含了一个新特性。现在,每个 Java 应用程序都有一个名为 common pool 的默认`ForkJoinPool`。您可以通过调用`ForkJoinPool.commonPool()`静态方法获取。您不需要显式地创建一个(尽管您可以)。默认情况下,此默认分叉/联接执行器将使用由计算机的可用处理器确定的线程数。您可以通过更改系统属性`java.util.concurrent.ForkJoinPool.common.parallelism`的值来更改此默认行为。
Java8 在 Fork/Join 框架中包含了一个新特性。现在,每个 Java 应用都有一个名为 common pool 的默认`ForkJoinPool`。您可以通过调用`ForkJoinPool.commonPool()`静态方法获取。您不需要显式地创建一个(尽管您可以)。默认情况下,此默认分叉/联接执行器将使用由计算机的可用处理器确定的线程数。您可以通过更改系统属性`java.util.concurrent.ForkJoinPool.common.parallelism`的值来更改此默认行为。
JavaAPI 的一些特性使用 Fork/Join 框架来实现并发操作。例如,`Arrays`类对数组进行并行排序的`parallelSort()`方法和 Java 8 中引入的并行流(后面将在[第 7 章](07.html#1CQAE2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 7. Processing Massive Datasets with Parallel Streams – The Map and Reduce Model")中介绍,*使用并行流处理海量数据集——Map and Reduce 模型*和[第 8 章](08.html#1GKCM1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 8. Processing Massive Datasets with Parallel Streams – The Map and Collect Model")、*使用并行流处理海量数据集–映射和收集模型*使用此框架。
尽管如此,该算法还是非常流行于对不同种类的项目进行聚类。为了测试我们的算法,您将实现一个应用程序来对一组文档进行集群。作为一个文档集合,我们采用了维基百科页面的简化版本,其中包含了我们在[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")中介绍的电影语料库信息,*从任务中获取数据–可调用和未来接口*。我们只拿了 1000 份文件。为了表示每个文档,我们必须使用向量空间模型表示。通过这种表示,每个文档都表示为一个数字向量,其中向量的每个维度表示一个单词或一个术语,其值是定义该单词或术语在文档中重要性的度量。
尽管如此,该算法还是非常流行于对不同种类的项目进行聚类。为了测试我们的算法,您将实现一个应用来对一组文档进行集群。作为一个文档集合,我们采用了维基百科页面的简化版本,其中包含了我们在[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")中介绍的电影语料库信息,*从任务中获取数据–可调用和未来接口*。我们只拿了 1000 份文件。为了表示每个文档,我们必须使用向量空间模型表示。通过这种表示,每个文档都表示为一个数字向量,其中向量的每个维度表示一个单词或一个术语,其值是定义该单词或术语在文档中重要性的度量。
从[第 2 章](02.html#KVCC1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 2. Managing Lots of Threads – Executors")*管理大量线程–执行器*,到[第 8 章](08.html#1GKCM1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 8. Processing Massive Datasets with Parallel Streams – The Map and Collect Model")*使用并行流处理海量数据集–映射和收集模型*,您使用 Java 并发 API 的最重要部分实现了不同的示例。通常,这些示例是真实的,但大多数情况下,这些示例可能是更大系统的一部分。例如,在[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")中*从任务获取数据–可调用和未来接口*中,您实现了一个应用程序来构建一个反向索引,用于信息检索系统。在[第 6 章](06.html#173722-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 6. Optimizing Divide and Conquer Solutions – The Fork/Join Framework")*优化分而治之的解决方案——Fork/Join 框架*中,您实现了 k-means 聚类算法对一组文档进行聚类。但是,您可以实现一个完整的信息检索应用程序,该应用程序读取一组文档,使用向量空间模型表示它们,并使用 K-NN 算法对它们进行聚类。在这些情况下,您有可能使用不同并发技术的不同部分(执行器、流等),但它们必须在它们之间进行同步和通信,以获得所需的结果。
从[第 2 章](02.html#KVCC1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 2. Managing Lots of Threads – Executors")*管理大量线程–执行器*,到[第 8 章](08.html#1GKCM1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 8. Processing Massive Datasets with Parallel Streams – The Map and Collect Model")*使用并行流处理海量数据集–映射和收集模型*,您使用 Java 并发 API 的最重要部分实现了不同的示例。通常,这些示例是真实的,但大多数情况下,这些示例可能是更大系统的一部分。例如,在[第 4 章](04.html#VF2I1-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 4. Getting Data from the Tasks – The Callable and Future Interfaces")中*从任务获取数据–可调用和未来接口*中,您实现了一个应用来构建一个反向索引,用于信息检索系统。在[第 6 章](06.html#173722-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 6. Optimizing Divide and Conquer Solutions – The Fork/Join Framework")*优化分治的解决方案——Fork/Join 框架*中,您实现了 k-means 聚类算法对一组文档进行聚类。但是,您可以实现一个完整的信息检索应用,该应用读取一组文档,使用向量空间模型表示它们,并使用 K-NN 算法对它们进行聚类。在这些情况下,您有可能使用不同并发技术的不同部分(执行器、流等),但它们必须在它们之间进行同步和通信,以获得所需的结果。
此外,本书中介绍的所有示例都可以使用 Java 并发 API 的其他组件实现。我们也将讨论其中一些备选方案。
在本章中,我们将介绍以下主题:
* 大数据块同步机制
* 文档集群应用程序的一个示例
* 实施备选方案
* 文档集群应用的一个示例
* 实现备选方案
# 大数据块同步机制
大型计算机应用程序由不同的组件组成,这些组件共同工作以获得所需的功能。这些组件必须在它们之间进行同步和通信。在[第 9 章](09.html#1LCVG2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 9. Diving into Concurrent Data Structures and Synchronization Utilities")中*深入到并发数据结构和同步实用程序*中,您了解到可以使用不同的 Java 类来同步任务并在它们之间进行通信。但是,如果要同步的组件也是可以使用不同机制实现其并发性的并发系统,则此任务组织会更加复杂。对于示例,您在应用程序中有一个组件,该组件使用 Fork/Join 框架生成结果,这些结果由使用`Phaser`类同步的其他任务使用。
大型计算机应用由不同的组件组成,这些组件共同工作以获得所需的功能。这些组件必须在它们之间进行同步和通信。在[第 9 章](09.html#1LCVG2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 9. Diving into Concurrent Data Structures and Synchronization Utilities")中*深入到并发数据结构和同步工具*中,您了解到可以使用不同的 Java 类来同步任务并在它们之间进行通信。但是,如果要同步的组件也是可以使用不同机制实现其并发性的并发系统,则此任务组织会更加复杂。对于示例,您在应用中有一个组件,该组件使用 Fork/Join 框架生成结果,这些结果由使用`Phaser`类同步的其他任务使用。
您已经在[第 7 章](07.html#1CQAE2-2fff3d3b99304faa8fa9b27f1b5053ba"Chapter 7. Processing Massive Datasets with Parallel Streams – The Map and Reduce Model")中*使用并行流处理海量数据集的过程中实现了这个示例—映射和简化模型*。这种算法希望获得关于一组非常大的数据的统计信息。您还可以使用并发 API 的以下组件实现此示例: