第10章-TwoPhaseTermination

[TOC]

10.1 模式简介

  1. 小孩子在玩玩具时经常会将玩具弄得满房间都是。晚上到了睡觉时间,妈妈就会对小孩子说:“先收拾房间再睡觉哦。” 这时,小孩子会开始打扫房间。
  2. 该模式的名字直译为中文是 “分两阶段终止” 的意思。它是一种先执行完终止处理再终止线程的模式。
分两阶段终止
  1. 我们称线程在进行正常处理时的状态为 “操作中”。在要停止该线程时,我们会发出 “终止请求”。这样,线程就不会突然终止,而是会先开始进行 “打扫工作”。我们称这种状态为 “终止处理中”。从 “操作中” 变为 “终止处理中” 是线程终止的第一阶段
  2. 在 “终止处理中” 状态下,线程不会再进行正常操作了。它虽然仍然在运行,但是只会进行终止处理。终止处理完成后,就会真正地终止线程。“终止处理中” 状态结束是线程终止的第二阶段
  3. 先从 “操作中” 状态变为 “终止处理中” 状态,然后再真正地终止线程。这就是 Two-Phase Termination模式。
  4. 该模式的要点如下:
    • 安全地终止线程(安全性)
    • 必定会进行终止处理(生存性)
    • 发出终止请求后尽快进行终止处理(响应性)

10.3 Two-Phase Termination模式中的角色

10.3.1 TerminationRequester(终止请求发出者)

  1. TerminationRequester 角色负责向 Terminator 角色发出终止请求。

10.3.2 Terminator(终止者)

  1. Terminator 角色负责接收终止请求,并实际执行终止处理。它提供了表示终止请求的shutdownRequest方法。shutdownRequest方法不需要使用Single Threaded Execution模式。
  2. 当shutdownRequest方法被调用后,Terminator角色会在考虑了安全性的基础上,自己进入 “终止处理中” 状态。接着,当终止处理结束后,Terminator角色就会终止自己。
  3. Terminator角色带有一个表示自己是否已经接收到终止请求的标志(门),在需要安全地开始终止处理时,会检查这个标志。如果能够频繁地检查该标志,就可以缩短接收到终止请求后变为“终止处理中 ”状态所需的时间。

10.4 拓展思路的要点

10.4.1 不能使用Thread类的stop方法

  1. java.lang.Thread类提供了用于强制终止线程的stop方法。但是stop是 “不推荐使用的方法”(deprecated方法),我们不应当使用它。
  2. 因为如果使用stop方法,实例的安全性就无法确保。使用stop方法后,线程会在抛出 Java.lang.ThreadDeath异常后终止。即使该线程正处于访问临界区的过程中(例如正在执行synchronized方法的过程中)也会终止。请看以下示例:
class Position
{
    private int x;
    private int y; 

    public synchronized void setXY (int newx, int newY)
    {
        x = newx;

        // 可能会在两条语句中间stop
        
        y = newY;
    }
}
  1. 如果使用 stop 方法终止线程,那么实例就会失去安全性。这是因为,线程可能会在赋值语句 x = newx 执行之后、赋值语句 y=newY 执行之前这个时间点终止。

10.4.2 仅仅检查标志是不够的

  1. 让我们来思考一下为何需要在 shutdownRequest 方法中调用 interrupt 方法。换言之,就是思考一下为什么只将 shutdownRequested 标志设为true是不行的。
  2. 原因很简单。因为当想要终止线程时,该线程可能正在sleep。而当线程正在sleep时,即使将shutdownRequested 标志设置为true,线程也不会开始终止处理。等到sleep时间过后,线程可能会在某个时间点开始终止处理,但是这样程序的响应性就下降了。如果使用interrupt方法的话,就可以中断sleep。
  3. 另外,线程当时也可能正在wait。而当线程正在wait时,即使将 shutdownRequested标志设为true,线程也不会从等待队列中出来,所以我们必须使用interrupt方法对线程下达 “中断wait” 的指示。

10.4.3 仅仅检查中断状态是不够的

  1. 调用interrupt方法后,如果线程正在sleep或是wait,那么会抛出 InterruptedException 异常,而如果不抛出异常,线程就会变为中断状态。那么能否不准备一个新的shutdownRequested 标志,而是通过捕获 InterruptedException,使用 isInterrupted 方法来检查线程是否处于中断状态?
  2. 如果开发人员可以看到线程的所有相关程序,那么就无需使用shutdownRequested标志。只要捕获InterruptedException,并使用 isInterrupted 方法就能够正确地开始终止处理。
  3. 但是,只要线程正在执行的方法中有一处忽略InterruptedException,上面的方法就可能行不通。“忽略InterruptedException” 是指像下面这样的代码片段:
try
{
    Thread.sleep(100);
}
catch (InterruptedException e)
{
    //忽略InterruptedException
}
  1. 这样,即使在wait、sleep、join状态时抛出了InterruptedException,线程也不会变为中断状态。也就是说,如果程序中没有shutdownRequested标志,而且有上面这样的代码,那么即使使用shutdownRequest方法发出了终止请求,该请求也不会被处理。
  2. shutdownRequested是用于记录是否已经发出终止请求的标志。(shutdownRequested 的意义)

10.4.4 优雅地终止线程

  1. “线程优雅地执行终止处理,然后终止运行” 这种状态用英语单词来形容的话,就是Graceful
    (优雅的、高贵的、得体的)。这种状态相当于工作的结束并不是慌慌张张地放下已经着手的工作不管,而是在进行必要的整理后才正式终止。Two-Phase Termination模式就是用来优雅地终止线程的模式。下面我们来看看Two-Phase Termination模式是如何体现 安全性、生存性、响应性三个要点的。

10.4.4.1 安全地终止(安全性)

  1. 即使接收到终止请求,线程也不会立即终止。首先表示是否已经接收到终止请求的shutdownRequested标志会被设置为true。然后,仅在线程运行至不会破坏对象安全性的位置时,程序才会开始终止处理
  2. 这就像是即使妈妈说了 “要睡觉了”,也不能慌慌张张地打扫房间导致弄坏玩具一样。

10.4.4.2 必定会进行终止处理(生存性)

  1. 线程在接收到终止请求后,会中断可以中断的 wait,转入终止处理。为此,shutdownRequest方法会调用 interrup t方法。
  2. 另外,为了确保在抛出异常后程序也会执行终止处理,我们使用了 try...finally 语句块。
  3. 这就像是不能让玩具散落一地就去睡觉一样。

10.4.4.3 发出终止请求后尽快进入终止处理(响应性)

  1. 线程在接收到终止请求后,会中断可以中断的 sleep,尽快进入终止处理。为此,shutdownRequest 方法会调用interrupt方法。
  2. 另外,在执行长时间处理前需要检查 shutdownRequested 标志。
  3. 这就像是如果被妈妈说了 “快收拾房间”,就要尽快地收拾房间。

10.7 java.util.concurrent 包与线程同步

10.7.1 java.util.concurrent.CountDownLatch类

  1. 使用 Java.util.concurrent.CountDownLatch类可以实现 “等待指定次数的CountDown方法被调用” 这一功能。
时序图

10.7.2 java.util.concurrent.CyclicBarrier类

  1. CyclicBarrier可以周期性地(cyclic)创建出屏障(barrier)。在屏障解除之前,碰到屏障的线程是无法继续前进的
  2. 屏障的解除条件是到达屏障处的线程个数达到了构造函数指定的个数。也就是说,当指定个数的线程到达屏障处后,屏障就会被解除,然后这些线程就会像听到了 “预备,走” 一样一起冲出去。
  3. 即可以用来实现 “除非 X 个线程都结束第 N 阶段的处理,否则哪个线程都不能进入第 N+1 阶段” 的功能。
时序图
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,848评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,529评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,824评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,329评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,227评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,879评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,218评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,877评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,159评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,155评论 2 315
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,987评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,736评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,273评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,407评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,663评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,158评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,517评论 2 339

推荐阅读更多精彩内容