java并发编程(七)线程的取消与关闭

中断

要使任务和线程安全、快速、可靠的停止下来并不是一件容易的事情。java没有提供任何机制来安全的终止线程。
但它提供了中断(Interruption),这是一种协作机制能够使一个线程终止另一个线程的当前工作。
通常,中断是实现取消的最合理方式。

中断是礼貌地请求另一个线程在它愿意并且方便的时候停止它正在做的事情。有些方法,例如 Thread.sleep(),wait,jion很认真地对待这样的请求,但每个方法不是一定要对中断作出响应。

interrupt()实现中断

Thread中断相关操作

  • interrupt: 用于中断目标线程
  • isInterrupted: 用于检测目标线程是否会中断
  • Thread.interrupted: 用于清除当前线程的中断状态,并返回之前的中断状态,这是清除中断状态的唯一方法

interrupt()会使线程抛出interruptedException,线程内捕捉该异常并处理结束任务比如跳出循环等。
注意线程内抛出interruptedException时一定要处理,如果不处理的话这个线程就屏蔽了中断。

Future实现取消

通常使用现有的类比自行编写更好,Future提供了这样的方法。
future.cancel(boolean a);a为ture时表示结束这个正在运行的任务,如果a为false表示如果这个任务还没运行的话就不要运行了。
所以在我们调用future.get的时候如果抛出异常,而且我们知道这个时候不需要结果时可以使用future.cancel(ture)取消任务。

处理不可中断请求

不是所有阻塞方法都能响应中断,例如I/O阻塞或者等待内置锁而阻塞,这种情况下中断请求除了设置中断状态外没有任何作用。
等待内置锁时线程认为它一定能获得锁所以不会理会中断请求,但是Lock类提供了一种允许等待锁的同时仍然能响应中断请求

停止基于线程的服务(线程池等)

关闭ExecutorService
ExecutorService
ExecutorService提供两个关闭的方法,shutdown 和shutdownNow。shutdownNow首先关闭当前执行线程,然后返回未执行的任务,而shutdown则等待执行完成。两种方法差别在于安全性和响应性。shutdown关闭的慢但是更加安全。

JVM关闭钩子

关闭钩子本质上是一个线程(也称为Hook线程),用来监听JVM的关闭。通过使用Runtime的addShutdownHook(Thread hook)可以向JVM注册一个关闭钩子。Hook线程在JVM 正常关闭才会执行,在强制关闭时不会执行。

对于一个JVM中注册的多个关闭钩子它们将会并发执行,所以JVM并不能保证它的执行顺行。Hook线程会延迟JVM的关闭时间,这就要求在编写钩子过程中必须要尽可能的减少Hook线程的执行时间。另外由于多个钩子是并发执行的,那么很可能因为代码不当导致出现竞态条件或死锁等问题,为了避免该问题,强烈建议在一个钩子中执行一系列操作。
例如通过Hook实现临时文件清理

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            public void run() {
                System.out.println("清理临时文件");
            }
        }));

总结

java并没有提供抢占式的机制来取消线程,它提供了了一种协作式的中断机制。Future和Executor框架可以帮助我们构建可取消的任务,避免我们手动构建。

发布了56 篇原创文章 · 获赞 4 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/xs925048899/article/details/104657534