Thread.interrupt 快速解读

        特性
        [Interrupt为什么有时候有用,有时候没用呢。]
  • Interrupt设置一个线程为中断状态
  • Interrupt操作的线程处于sleep,wait,join 阻塞等状态的时候,会抛出一个InterruptedException
  • Interrupt操作的线程在可中断通道上因调用某个阻塞的 I/O 操作(serverSocketChannel. accept()、socketChannel.connect、socketChannel.open、 
    socketChannel.read、socketChannel.write、fileChannel.read、fileChannel.write),会抛出一个ClosedByInterruptException
  • 我们通过try/catch捕获后则可进行return/break/throw new XXException()等方式返回来销毁或结束线程

          下面来看例子
         第一个例子解释了为什么Interrupt执行后线程依然没有中断
         后两个例子针对I/O阻塞以及sleep等状态进行了中断操作

 例子1.
/**
 * 常规interrupt
 * 
 * @author Allen
 * @date 2017年2月21日
 *
 */
public class e1 implements Runnable {
	public static void main(String[] args) {
		e1 nm=new e1();
		Thread thread = new Thread(nm);
		System.out.println("躁起来修电脑去");
		System.out.println("interrupt state = " + thread.isInterrupted());
		thread.start();
		nm.sleep(500);
		thread.interrupt();
		System.out.println("别修复了,世界末日了");
		System.out.println("interrupt state = " + thread.isInterrupted());
	}

	public void run() {
		System.out.println("开始修复电脑");
		for (int i = 10; i <= 100; i += 10) {
			if(Thread.interrupted())
				System.out.println("~~别烦我我得修完了");
			System.out.println("修复进度" + i + "%");
			sleep(200);
		}
		System.out.println("修复完毕");

	}
	/**
	 * 自己写个sleep条件循环为了禁止Interrupt对Thread.sleep(x)时的异常抛出
	 * @param step
	 * @author Allen
	 * @date 2017年2月21日
	 */
	private void sleep(int step) {
		long time = System.currentTimeMillis();
		while ((System.currentTimeMillis() - time < step)) {
		}
	}
}

执行结果
躁起来修电脑去
interrupt state = false
开始修复电脑
修复进度10%
修复进度20%
修复进度30%
别修复了,世界末日了
interrupt state = true
~~别烦我我得修完了
修复进度40%
修复进度50%
修复进度60%
修复进度70%
修复进度80%
修复进度90%
修复进度100%
修复完毕

上面可见在线程启动后我们在nw.sleep(500)后,针对启动的线程进行了thread.interrupt(),然而thread.isInterrupted()也返回了true,但是线程依然正在运行。因为我们这里的sleep是自己写的并不是用的Thread.sleep或io通道所以无法通过exception进行线程终端捕获,线程也不会抛出exception

例子2.
/**
 * interrupt try/catch销毁版
 * 
 * @author Allen
 * @date 2017年2月21日
 *
 */
public class e2 implements Runnable {
	public static void main(String[] args) throws Exception {
		e2 nm = new e2();
		Thread thread = new Thread(nm);
		System.out.println("躁起来修电脑去"); 
		System.out.println("interrupt state = " + thread.isInterrupted());
		thread.start();
		Thread.sleep(500);
		thread.interrupt();
		System.out.println("别修复了,世界末日了");
		/**
		 * 因为Thread.sleep 触发了中断状态 所以interrupted状态被清除
		 * 所以这里打印的也是false
		 */
		System.out.println("interrupt state = " + thread.isInterrupted());
	}

	public void run() {
		System.out.println("开始修复电脑");
		for (int i = 10; i <= 100; i += 10) {
			if (Thread.interrupted())
				System.out.println("~~别烦我我得修完了");
			System.out.println("修复进度" + i + "%");
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
					System.out.println("抛异常了被try/catch死神捕获了,只能return了");
					return;
				}
		}
		System.out.println("修复完毕");

	}

}

输出

躁起来修电脑去
interrupt state = false
开始修复电脑
修复进度10%
修复进度20%
修复进度30%
别修复了,世界末日了
interrupt state = false  //这里为什么返回false了呢?
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at TwoPhaseTerminationPattern.interrupt.e2.run(e2.java:34)
	at java.lang.Thread.run(Thread.java:724)
抛异常了被try/catch死神捕获了,只能return了

可见例子2中因为是用了Thread.sleep,我们在调用interrupt的时候成功的在目标线程中抛出了InterruptedException,从而我们可以进行一些列操作
对于interrupte state为什么在这个成功捕获的异常下居然返回false了。

我们看一下API

public boolean isInterrupted()
Tests whether this thread has been interrupted. The interrupted status of the thread is unaffected by this method.
A thread interruption ignored because a thread was not alive at the time of the interrupt will be reflected by this method returning false.

Returns:
true if this thread has been interrupted; false otherwise.
See Also:
interrupted()

原来是因为当抛出exception后线程中断重置状态了所以返回false了

例子3 io阻塞下的interrupt

/**
 * interrupt i/o阻塞
 * 
 * @author Allen
 * @date 2017年2月21日
 *
 */
public class e3 implements Runnable {
	public static void main(String[] args) throws Exception {
		e3 nm = new e3();
		Thread thread = new Thread(nm);
		System.out.println("燥起来修电脑去");
		System.out.println("interrupt state = " + thread.isInterrupted());
		thread.start();
		Thread.sleep(800);
		thread.interrupt();
		System.out.println("别修复了,世界末日了");
		System.out.println("interrupt state = " + thread.isInterrupted());
	}

	public void run() {
		System.out.println("开始修复电脑");
		for (int i = 10; i <= 100; i += 10) {
			if (Thread.interrupted())
				System.out.println("~~别烦我我得修完了");
			System.out.println("修复进度" + i + "%");
			if (i == 70) {
				try {
					System.out.println("建立一个nio ServerSocketChannel我就继续修复");
					ServerSocketChannel ss = ServerSocketChannel.open();
					ss.socket().bind(new InetSocketAddress(4488));
					System.out.println("建立好了");
					while (true) {
						// 阻塞一下
						ss.accept();
					}
				} catch (IOException e) {
					e.printStackTrace();
					System.out.println("抛异常了被try/catch死神补货了,只能return了");
					return;
				}
			}

		}
		System.out.println("修复完毕");

	}
}

输出

燥起来修电脑去
interrupt state = false
开始修复电脑
修复进度10%
修复进度20%
修复进度30%
修复进度40%
修复进度50%
修复进度60%
修复进度70%
建立一个nio ServerSocketChannel我就继续修复
建立好了
别修复了,世界末日了
interrupt state = true  //这里怎么又出现true了,捕获了exception不是应该重置状态么?
java.nio.channels.ClosedByInterruptException
	at java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:202)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:248)
	at TwoPhaseTerminationPattern.interrupt.e3.run(e3.java:41)
	at java.lang.Thread.run(Thread.java:724)
抛异常了被try/catch死神补货了,只能return了

为什么io例子中interrupt的状态又成了true?
又翻了翻API

public void interrupt()
Interrupts this thread.
Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.

If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.

If none of the previous conditions hold then this thread's interrupt status will be set.

Interrupting a thread that is not alive need not have any effect.

Throws:
SecurityException - if the current thread cannot modify this thread


没关系还有中文的jdk7

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

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

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

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

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

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

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

可以看到当wait,join.sleep因interrupt而抛出InterruptedExcetion前,还会清除/重置其中断状态为false,所以例子2中显示为false
然而IO操作中,仅仅是抛出一个ClosedByInterruptException 所以interrupted显示true



就到这里了,相信大家对interrupt的用法已经有一定了解了。



你可能感兴趣的:(总结,Java)