androidThe Magnificent JavaJava学习笔记

多线程基础之安全的停止线程

2017-03-05  本文已影响185人  承香墨影

版权声明:

本账号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影所有。

允许有条件转载,转载请附带底部二维码。

一、前言

继续接昨天的内容,昨天讲解了Java下多线程的使用。但是能舞的起来是徒弟,能停的优雅才是师傅。接下来让我们看看,如何优雅的停止一个线程。

二、安全的停止线程

1、安全停止涉及到的方法

当开启一起线程去进行任务之后,如果需要被停止,意味着它将放弃当前正在进行的操作。而在Java中,停止一个线程并不像return一个方法一样干脆利落,想要安全的停止线程,需要一些跟优雅的技巧。

如果想要安全的停止一个线程,需要借助Thread.interrupt()方法,它的本意是停止、终止的意思,但是实际上,它并不会直接终止掉一个正在运行的进程,而是在当前线程中,打一个需要『被停止』的标签,而是否停止应该由当前线程自己决定,所以这也决定了我们需要在编写Thread或者Runnable代码的时候,有更高的要求,要明确自己如何被安全的停止。

Paste_Image.png

interrupt()的解释确实挺多,接下来看看它是如何使用的。

既然interrupt()只是为我们对当前线程做了一个简单的停止标记,而JDK同时也为我们提供了获取这个标记值的API。

Paste_Image.png

通过源码可以看到它们的区别,interrupted()是一个static的方法,并且操作的是当前代码运行的当前线程,而isInterrupted()方法缺失操作的是指定线程。它们最终都会调用isInterrupted(boolean)的方法。再来看看这个方法。

Paste_Image.png

可以看到,这个方法是一个native的方法,参数表示是否需要清理这个Interrupted的状态。

2、具体看看这些方法的用处

举个例子看看如何区分这两个方法:

Paste_Image.png

1为停止,表示检查的是mt这个线程,而2为没停止,是因为检查的是当前运行环境的线程,即为主线程。

这个例子本身没问题,也讲清楚了原本的意思。但是实际上,interrupt()方法和interrupted()方法并不是线程安全的,也就是说,如果使用interrupt()方法停止了一个线程,立即使用interrupted()方法去检查,可能会回去到还没有被停止的结果。

前面介绍到,interrupt()和isInterrupted()方法最终都会调用一个native的isInterrupted(boolean)的方法,这个方法的参数主要是为了确定是否需要清理interrupted的状态。

下面举两个例子就清楚了。

先看看Thread.interrupted()。

Paste_Image.png

可以看到,第一次标记为true,但是获取完之后,立即就被清理掉了interrupt状态,再去获取,就标记为false。再看看isInterrupted(),它是不会清理掉状态的。

Paste_Image.png

3、需要安全停止的线程

那么继续改造一下上面的例子,如果想在线程被停止之后,立即停止掉循环,就可以在循环中,每次调用都检查一下当前线程是否已经被停止了。如果被停止了,直接return出去,或者做一些清理工作再退出。

Paste_Image.png

4、在sleep的时候,停止线程会发生什么

当前线程有可能在运行状态,也可能在sleep的状态,如果在sleep的状态下,interrupt一个线程,会发生什么?

从调用sleep的时候就应该发现,它是会抛出一个InterruptedException异常的,这里就是专门为了捕捉在sleep的时候,被interrupt的情况。如果出发,将进入catch。并且置换interrupt状态为false,所以这里触发了到sleep的catch的时候,一定要有后续的操作,不要再依赖那两个判断线程终止的方法来判断了。

三、如何非安全的停止线程

既然推荐用安全的方式来停止线程,那么不安全的方式又需要怎么做呢?不安全的方式其实本身不推荐使用,但是研究一下为什么不安全也有利于我们理解线程安全。

不安全的方式,就涉及到Thread的几个已经被标记为@Deprecated的方法,就是说,已经被废弃了,可能引发不可预料的问题,不推荐使用。

这个方法就是stop()方法,和名称一样,它的作用就是停止线程。

stop()能不能做到立即停止线程?能,除了它的一些不可能预料的数据问题之外,stop方法真的非常的好用,停止线程到简单直接,直接被停止之后,后面的代码根本不会得到执行,这样会导致一些清理工作没法完成,并且stop会直接释放当前获取到的锁,而如果当前正好在修改加锁的数据的时候,被强制停止了,就会导致数据被改了一半,导致数据不一致的情况。

既然不推荐使用,那就简单举个例子,不再写demo了。

假设一个人做生意,卖书,库房里存了需要卖的书,每次的流程是从库房里拿出来一本书,卖出去之后,把钱存入银行账户,再去取一本书继续卖。假设有一天,这个人从库房取了一本书卖出去了,正在去银行存钱的路上,被警察逮捕了(stop),接下来他就没办法完成去银行存钱的任务了。这个时候对书的库存和银行账户上的金额,就对不上了,因为出库了一本书,缺没有相应的金钱入账。这样的一个数据不一致,就是线程不安全。

有一点需要注意一下,stop()方法的时候,会触发ThreadDead异常,但是它不需要被显示Catch住,大家只需要知道有这么个概念就可以了。

四、结语

到现在基本上就讲解清楚了子线程的创建和停止。既然已经被废弃的方法,最好还是不要去使用它,建议使用安全的方式去停止线程。

公众号二维码.jpg
上一篇 下一篇

猜你喜欢

热点阅读