写在前面

本文隶属于专栏《100个问题搞定Java并发》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和文献引用请见100个问题搞定Java并发

解答

在Java语言中,可以使用stop方法与suspend方法来终止线程的执行。

Thread.stop()可能会导致锁定的资源对象出现数据不一致的问题,Thread.suspend()可能会导致死锁问题。

鉴于以上两种方法的不安全性,Java语言己经不建议使用以上两种方法来终止线程。
那么,如何才能终止线程呢? 一般建议采用的方法是让线程自行结束,进入Dead (死亡)状态。
一个线程要进入Dead状态,就是执行完run方法,也就是说,如果想要停止一个线程的执行,就要提供某种方式让线程能够自动结束run方法的执行。

在实现的时候,可以通过设置一个flag标志来控制循环是否执行,通过这种方法来让线程离开run方法,从而终止线程。

补充

Thread.stop()的问题

使用Thread.stop() 方法来终止线程时,它会释放该线程所持有的所有的锁。
一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用thread.stop()后导致了该线程所持有的所有锁的突然释放,
那么被保护数据就有可能呈现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。

Thread.suspend()的问题

suspend方法的使用容易引起死锁。

由于调用suspend方法不会释放锁,这就会导致一个问题:如果使用一个suspend挂起一个有锁的线程,那么在锁恢复之前将不会被释放。
如果调用suspend 方法的线程试图取得相同的锁,程序就会发生死锁。

例如,线程A已经获取到了互斥资源M的锁,然后调用suspend方法挂起了A的执行,如果没有线程唤醒线程A且线程B也去访问互斥资源,此时线程B 就会出现冻结无法执行下去了,也可以理解为出现了死锁。

安全终止线程的方法

  1. 使用violate boolean变量来标识线程是否停止

  2. 停止线程时,需要调用停止线程的interrupt()方法,因为线程有可能在wait()或sleep(), 提高停止线程的即时性

  3. 对于blocking IO的处理,尽量使用InterruptibleChannel来代替blocking IO

  4. 如果程序因为IO而停滞,进入非运行状态,基本上要等到IO完成才能离开这个状态,在这种情况下,无法使用interrupt来使程序离开run方法。需要使用一个替代的方法,其基本思路也是触发一个异常,而这个异常与所使用的IO相关,例如,如果使用BufferedReader#readLine方法在等待网络上的一个信息,此时线程处于阻塞状态。让程序离开run的方法就是使用close方法来关闭流, 在这种情况下会引发IOException异常,run方法可以通过捕获这个异常来安全结束线程。

Q.E.D.


Apache Spark Contributor