多线程学习之如何中断线程

在很多时候我们需要中断或者取消一些任务,在Java中并没有提供一些好的方法来终止线程。

中断原因

我们的任务或者线程一般情况下都会让它正常的执行直到结束,然而有时候也有可能我们需要提前结束这个任务或者线程。但是一个任务或者线程的执行涉及系统、内存、栈、数据等的完整性,要提前结束并不简单,在Java中也没有提供好的安全地终止线程

取消的原因有很多比如用户取消、一定时间未成功提前结束、错误、服务器关闭等,一个好的软件特点之一就是能够很完善的处理失败、关闭和取消的过程。

中断方法一:中断标志位

我们可以设置一个已关闭的标志位,当任务或者线程运行的时候先判断标志位的状态,如果是已经关闭那个这个任务或者线程就直接结束,不过这个标志位需要用volatile关键字修饰,否则可能其他线程已经修改了任务可能仍然在运行。

这种方法可以解决一部分问题,但是当任务可能会被阻塞的时候就会出现问题,就像之前的生产者、消费者模式,如果生产者通过循环往队列里面加元素,在每次循环之前都要判断中断标志位,如果结束了就不往队列中put数据了,当消费者在某些情况下可能不在消费数据所以会设置标志位为已结束。此时如果阻塞队列是满的,而刚好生产者在put阻塞中,由于消费者不在消费,生产者线程就会永远处于阻塞状态。

中断方法二:Thread.interrupt()

上一个中断方法在遇到阻塞方法时就会出现永久阻塞状态的问题,所以Java的Thread提供了一个boolean类型的中断状态,通过interrupt方法可以设置状态为中断,isInterrupted方法会返回中断状态,静态的interrupted方法会清除当前线程的中断状态,并返回它之前的值,这是清除中断状态的唯一方法。

一些阻塞方法如Thread.sleep、Object.wait、阻塞队列的take、put方法都会检查线程中断状态,并且在发现中断时提前返回,他们响应中断时执行的操作包括:清除中断状态,抛出InterruptedException,表示阻塞操作因为中断而提前操作,这就是这些方法都会抛出InterruptedException的原因,反之如果抛出InterruptedException则说明线程被中断,接受到这个信息后我们可以方便的处理后续流程。

interrupt方法并不会真正的中断一个正在运行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己,这样才能保证数据结构不会被破坏。同时要小心调用interrupted方法,它会清除当前线程的中断状态,所以在方法的返回值是true时除非你本来想屏蔽这个中断,否则必须要处理,可以抛出InterruptedException或者再次调用interrupt中断线程。

中断方法三:利用Future

可以把任务封装成一个Future,Future中有一个方法“boolean cancel(boolean mayInterruptIfRunning);”如果参数为true并且任务正在某个线程中执行,那么这个线程就能够被中断,如果参数为false则表示如果任务还没有运行那就不要运行(有些任务不处理中断)。

还存在一些情况可能通过以上方法仍然无法中断或取消,比如IO阻塞或者等待获取锁的阻塞,不过Java中也有一些解决办法,比如Socket则是可以通过关闭socket,对于锁可以在Lock类中提供了lockInterruptibly方法,它可以支持在等在一个锁的同时去响应中断信号。

JVM的关闭

JVM关闭也分为正常关闭和强行关闭,强行关闭方式比如杀死JVM进程。这里主要说明的是正常关闭,比如System.exit获取程序正常执行结束。在正常关闭时,JVM会首先调用注册的关闭钩子(通过“Runtime.getRuntime().addShutdownHook();”添加的一些关闭程序时必须执行的方法,比如清理一些临时文件之类的),当钩子关闭完成后JVM会运行终结器,最后停止。JVM关闭并不会关闭正在运行中的线程,而是在JVM关闭完成后强行关闭。如果关闭钩子或者终结器没有执行完成,那么JVM的关闭进程就会被挂起,然后强行关闭JVM。

两个重要知识点:

线程分两种:普通线程和守护线程,jvm启动时创建的线程除了主线程外都是守护线程,当创建一个线程时新线程会继承状态,所以主线程默认情况下创建的线程都是普通线程。

当一个线程退出时JVM会检查其他正在运行的线程,如果所有都是守护线程,那么JVM会执行正常退出操作。

终结器:垃圾回收器对那些定义了finalize方法的对象在回收后会调用finalize方法,不过finalize方法有性能问题,所以现在已经避免使用。

总结

启动一个任务或线程很简单,但是要提前取消或者关闭却比较复杂,一个好的软件是应该能够很好的支持取消和关闭的。

Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!


你可能感兴趣的:(多线程学习之如何中断线程)