前言
提示:线程的结束可以分为正常结束,和异常结束。结束线程有两种方式:1.是用stop方法,不过这个方法是强行结束正在运行的线程,会存在数据不一致的问题,已经废弃,2.是用interrupte status ,本文主要介绍2。
一、认识中断标志位
1. interrupted()
interrupt方法用于中断线程。调用该方法的线程的状态将被置为"中断"状态。如何使用:
- 线程中断仅仅是改变线程的中断状态位,不会停止线程。
- 需要用户自己去监视线程的状态位并做出相应处理。支持线程中断的方法(也就是线程中断后会抛出interruptedException的方法)就是在监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,就会抛出中断异常。
对于2我们来说明下:
public class 中断线程 {
public static void main(String[] args) throws InterruptedException {
try {
InterruptService interruptService = new InterruptService();
Thread thread = new Thread(interruptService);
thread.start();
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
private static class InterruptService implements Runnable {
//如果使用Callable接口中call方法异常就会得以扩散
@Override
public void run() {
try {
System.out.println( "begin run" );
//重要:无论是先中断还是先阻塞都能达到停止线程的目的,只要两者配置使用就可以到达效果
// 这里的中断只是设置了中断标志位,而无法真正的中断线程。除非和以下三种方式结合
/**
* * <p> If this thread is blocked in an invocation of the {@link
* * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* * class, or of the {@link #join()}, {@link #join(long)}, {@link
* * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* * methods of this class, then its interrupt status will be cleared and it
* * will receive an {@link InterruptedException}.
*
* 这里说明了在经历阻塞方法时,中断状态就被清空了,同时还要抛出一个中断异常
*/
Thread.currentThread().interrupt();
System.out.println(Thread.currentThread().isInterrupted());
//方式一,线程进入sleep
Thread.sleep( 10 );
//方式二、join
// Thread.currentThread().join();
//方式三、wait
// Thread.currentThread().wait();
System.out.println( "begin end" );
} catch (Exception e) {
/**
* * Tests whether the current thread has been interrupted. The
* * <i>interrupted status</i> of the thread is cleared by this method. In
* * other words, if this method were to be called twice in succession, the
* * second call would return false (unless the current thread were
* * interrupted again, after the first call had cleared its interrupted
* * status and before the second call had examined it).
*/
System.out.println(Thread.currentThread().isInterrupted());
System.out.println(Thread.currentThread().isInterrupted());
System.out.println("先interrupt再阻塞后终止了");
e.printStackTrace();
}
}
}
}
上面所示的也是一个当发生中断异常时,也就结束了线程的示例。我们来看下sleep方法:
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;
我们看抛出异常时的javadoc,就可以发现,当前线程被中断时,就会清除当前状态标志位,然后报出异常,当然这里没有显示的写出检查线程状态标志位 的代码,这里是jvm去处理了。我们可以看AbstractQueuedSynchronizer的await方法,就显示的去检查了线程的中断状态。
2. interrupted() vs isInterrupted()
点进源码,我们发现都是调用了isInterrupted(boolean ClearInterrupted)。他们都是查看的方法,参数为true则是重置中断标志,否则只是查看并不重置(isInterrupted()是只查看)。
二、InterrupteException的处理
上面我们提到了中断标志位的设置和查看,还提到了阻塞方法(即会一直检查标志位,并会抛出中断异常的方法)会使线程真正的中断,那么下面我们就来说下,抛出异常后我们要怎么处理。
- 直接向上层抛出
- 捕获并做业务处理
- 线程的run方法中捕获后,应继续设置中断状态为true,以保留证据,使得其他地方可见
详情参考