线程中断

线程中断​是什么​​​​​​

一个线程在未正常结束之前, 被强制终止是很危险的事情. 因为它可能带来完全预料不到的严重后果. 所以你看到Thread.suspend, Thread.stop等方法都被Deprecated了。那么不能直接把一个线程搞挂掉, 但有时候又有必要让一个线程死掉, 或者让它结束某种等待的状态 该怎么办呢? 优雅的方法就是, 给那个线程一个中断信号, 让它自己决定该怎么办

如何中断一个线程

Thread类的一个公共非静态方法

public void interrupt()

中断线程。

public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

我们通过翻译源码的Comments看看中断能做什么

1.如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess 方法就会被调用,这可能抛出 SecurityException。

2.如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。

3.如果该线程在可中断的通道上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException。

4.如果该线程在一个 Selector 中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup 方法一样。

5.如果以前的条件都没有保存,则该线程的中断状态将被设置。

6.中断一个不处于活动状态的线程不需要任何作用。

抛出:

SecurityException - 如果当前线程无法修改该线程

看完源码,很容易理解第一点,当你在当前线程执行interrupt时,如果不是当前线程,则会校验checkAccess

第二点,首先join方法能被中断的原因是wait被唤醒了,从join的源码就可以看出,至于wait和sleep方法能被唤醒,我认为是interrupt0完成的,因为只有这一个是native方法

第三点和第四点,是因为他们设置了blocker

用法经验

 interrupt用途: unBlock操作,支持任务cancel, 数据清理等。

两条实践原则:

1.Don't swallow interrupts (别吃掉Interrupt,一般是两种处理:  继续throw InterruptedException异常。  另一种就是继续设置Thread.interupt()异常标志位,让更上一层去进行相应处理。

2.Implementing cancelable tasks with Interrupt (使用Thread.interrupt()来设计和支持可被cancel的task)

注册Interrupt处理事件

我们的应用程序要处理cancel任务,一般都是采取主动轮询Thread.isInterrupt()来检测是否中断,这种方式的不好之处是一方面对我们的业务代码存在嵌入性,另一方面就是存在延迟,线程不可能一直在检查点检查是否中断

所以我们可以编写一个自定义的实现Interruptible接口的处理类,然后在打断线程前通过

sun.misc.SharedSecrets.getJavaLangAccess().blockedOn

的方式注入我们的处理类

当线程被打断时,会主动调用我们处理类中的interrupt方法

可中断的NIO就是通过这种方式实现的,参见AbstractInterruptibleChannel源码

package niube.thread;

import sun.nio.ch.Interruptible;

public class InterruptDemo {

	public static void main(String[] args) {
		MyThread myThread = new MyThread();
		sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(myThread, new MyInterruptHandler());
		myThread.start();
		myThread.interrupt();
	}

	static class MyThread extends Thread {
		static volatile boolean flag = true;
		@Override
		public void run() {
			while (flag)
				yield();
		}
	}
	static class MyInterruptHandler implements Interruptible {

		@Override
		public void interrupt(Thread thread) {
			if (thread instanceof MyThread) {
				((MyThread) thread).flag = false;
				System.out.println("thread is interrupted");
			}
		}
		
	}
}

 

没有更多推荐了,返回首页