第5章Producer-Consumer模式
Producer是生产者的意思,指的是生成数据的线程。Consumer则是"消费者"的意思,指的是使用数据的线程。生产者安全地将数据交给消费者。但当虽然仅是这样看似简单的操作,
但当生产者和消费者以不同的线程运行时,两者之间的处理速度差异便会引起问题。例如,消费者想要获取数据,可数据还没生成,或者生产者想要交付数据,而消费者的状态还无法接收数据等。Producer-Consumer模式在生产者和消费者之间加入了一个
“桥梁角色”。
该桥梁角色用于消除线程间处理速度的差异。一般来说,在该模式中,生产者和消费者都有多个,当然生产者和消费者有时也会只有一个。当两者都有一个时,我们称为Pipe模式。
第 6 章 Read-Write Lock 模式
6.1 Read-Write Lock模式
学生们正在一起看老师在黑板上写的板书。这时,老师想擦掉板书,再写新的内容。而学生们说道:“老师,我们还没看完,请先不要擦掉!”于是,老师就会等待大家都看完。
本章,我们将学习Read-Write Lock 模式。
当线程“读取”实例的状态时,实例的状态不会发生变化。实例的状态仅在线程执行“写入”操作时才会发生变化。从实例的状态变化这个观点来看,“读取”和“写入”有着本质的区别。
在Read-Write Lock模式中,读取操作和写入操作是分开考虑的。在执行读取操作之前,线程必须获取用于读取的锁。而在执行写入操作之前,线程必须获取用于写入的锁。
由于当线程执行读取操作时,实例的状态不会发生变化,所以多个线程可以同时读取。但在读取时,不可以写入。当线程执行写入操作时,实例的状态就会发生变化。因此,当有一个线程正在写入时,其他线程不可以读取或写入。
一般来说,执行互斥处理会降低程序性能。但如果把针对写入的互斥处理和针对读取的互斥处理分开来考虑,则可以提高程序性能。
第7章 Thread-Per-Message模式
7.1 Thread-Per-Message模式
上司把文件递给下属:“能帮我传真一下这个文件吗?”妻子告诉丈夫:“老公,帮忙倒一下垃圾”。像这样将工作委托给其他人的情况很常见。这个人把工作拜托给别人之后,就可以返回继续做自己的工作。
本章,我们将学习 Thread-Per-Message 模式。
所谓 Per,就是“每~”的意思。因此,Thread Per Message 直译过来就是“每个消息一个线 程”的意思。Message在这里可以理解为“命令”或“请求”。为每个命令或请求新分配一个线程, 由这个线程来执行处理——这就是Thread-Per-Message模式。
在 Thread-Per-Message 模式中,消息的“委托端”和“执行端”是不同的线程。消息的委托端线程会告诉执行端线程“这项工作就交给你了”。
第 8章 Worker Thread 模式
8.1 Worker Thread 模式
这是一个来自工作车间的故事。在这里,工人们负责组装塑料模型。客户会将很多装有塑料模型的箱子带到工作车间来,然后摆放在桌子上。
工人必须将客户送过来的塑料模型一个一个组装起来。他们会先取回放在桌子上的装有塑料模型的箱子,然后在阅读了箱子中的说明书后开始组装。当一箱模型组装完成后,工人们会继续去取下一个箱子。当所有模型全部组装完成后,工人们会等待新的模型被送过来。
本章,我们将学习 Worker Thread 模式。
Worker 的意思是工作的人、劳动者。在 Worker Thread 模式中,工人线程(worker thread )会 逐个取回工作并进行处理。当所有工作全部完成后,工人线程会等待新的工作到来。
Worker Thread 模式也被称为Background Thread (背景线程)模式。另外,如果从“保存多个 工人线程的场所”这一点来看,我们也可以称这种模式为Thread Pool (线程池)模式。
第9章 Future 模式
9.1 Future 模式
假设我们去蛋糕店买蛋糕。下单后,店员一边递给我们提货单,一边说“请您傍晚再来取蛋糕”。到了傍晚,我们就拿着提货单去取蛋糕。这时,店员会先和我们说“您的蛋糕已经做好了”,然后将蛋糕递给了我们。
本章,我们将学习 Future 模式。
Future 的意思是未来、期货(经济学用语)。假设有一个方法需要花费很长时间才能获取运行结果。那么,与其一直等待结果,不如先拿一张“提货单”。获取提货单并不耗费时间。这里的“提货单”我们就称为 Future 角色。
获取 Future 角色的线程会在稍后使用 Future角色来获取运行结果。这与凭着提货单去取蛋糕非常相似。如果运行结果已经出来了,那么直接领取即可;如果运行结果还没有出来,那么需要等待结果出来。
Future 角色是购买蛋糕时的提货单、预购单、预约券,是“未来”可以转化为实物的凭证。建议大家在阅读本章之前先学习Thread-Per-Message模式(第7章)的相关知识。
第10章 Two-Phase Termination 模式
10.1 Two-Phase Termination模式
小孩子在玩玩具时经常会将玩具弄得满房间都是。晚上到了睡觉时间,妈妈就会对小孩子说:“先收拾房间再睡觉哦。”这时,小孩子会开始打扫房间。
本章,我们将学习Two-Phase Termination模式。
该模式的名字直译为中文是“分两阶段终止”的意思。它是一种先执行完终止处理再终止线程的模式(图 10-1)。
我们称线程在进行正常处理时的状态为“操作中”。在要停止该线程时,我们会发出“终止请求”。这样,线程就不会突然终止,而是会先开始进行“打扫工作”。我们称这种状态为“终止处理中”。从“操作中”变为“终止处理中”是线程终止的第一阶段。
在“终止处理中”状态下,线程不会再进行正常操作了。它虽然仍然在运行,但是只会进行终止处理。终止处理完成后,就会真正地终止线程。“终止处理中”状态结束是线程终止的第二阶段。
先从“操作中”状态变为“终止处理中”状态,然后再真正地终止线程。这就是Two-Phase
Termination 模式。
该模式的要点如下。
安全地终止线程(安全性)
必定会进行终止处理(生存性)
发出终止请求后尽快进行终止处理(响应性)
第11章 Thread-Specific Storage 模式
11.1 Thread-Specific Storage模式
有一个储物间,里面并排摆放着许多储物柜。一个人拿着自己的钥匙进入了储物间,出来时手上拿着自己的行李。别人也拿着自己的钥匙进入了储物间。但是,虽然进入的是同一个储物间,打开的当然是另外一个储物柜。使用者都会从各自的储物柜中取出自己的行李。
本章,我们将学习 Thread-Specific Storage 模式。
Specific是“特定的”的意思,Storage是储存柜、存储装置的意思。因此,所谓ThreadSpecific Storage 就是“每个线程特有的存储柜”“为每个线程准备的存储空间”的意思。
Thread-Specific Storage 模式是一种即使只有一个人口,也会在内部为每个线程分配特有的存储 空间的模式。
Thread-Specific Storage模式还有以下名称。
Per-Thread Attribute(线程各自的属性)
在Java标准类库中,java,lang,ThreadLocal类实现了该模式。
12.Active Object 模式
12.1 Active Object 模式
在公司里,许多人都在工作着。有接待人员、销售人员、生产产品的工人、管理人员,还有负责发货和搬运产品的人……正是这些各个岗位上的人们互相协作,公司才能正常运营。如果将公司看作一个整体,它就是一个具有人格的组织——法人。
本章,我们将学习 Active Object 模式。
Active 是“主动的”的意思,因此 Active Object 就是“主动对象”的意思。所谓“主动的”, 一般指“有自己特有的线程”。因此,举例来说,Java的java.lang.Thread类的实例就是一种主动对象。
不过,在 Active Object 模式中出场的主动对象可不仅仅“有自己特有的线程”。它同时还具有可以从外部接收和处理异步消息并根据需要返回处理结果的特征。
消息。Active Object 模式中的主动对象会通过自己特有的线程在合适的时机处理从外部接收到的异步
在 Active Object模式中,组成主动对象与许多自然人组成法人类似。即使是Java 语言这样没有异步消息的编程语言,也可以使用 Active Object 模式组成实际上能够处理异步消息的主动对象。
Active Object模式综合了 Producer-Consumer模式(第 5 章)、Thread-Per Message 模式(第 7章)、 Future模式(第9 章)等各种模式。因此,建议大家在开始阅读本章之前,先阅读其他相关章节。
Active Object 模式有时也被称为Actor 模式 和 Concurrent Object 模式。