java并发:中断一个正在运行的线程
要使任务和线程能安全可靠地停止,并不是一件很容易的事情,java没有提供任何机制来安全地终止线程,那么我们该怎么办呢?
下面我们先来了解一下java中的中断机制:
Java 中的线程中断是 一种线程间的协作机制。
也就是说在某个线程中对另一个线程调用interrupt()方法并不能直接终止该线程,需要被中断的线程自己处理中断请求
isInterrupted()和interrupted() 的主要区别
非静态方法isInterrupted()用来查询某线程的中断状态,且不会改变该线程的中断状态标识。
源代码的定义如下:
/** * Tests whether this thread has been interrupted. The <i>interrupted * status</i> of the thread is unaffected by this method. * * <p>A thread interruption ignored because a thread was not alive * at the time of the interrupt will be reflected by this method * returning false. * * @return {@code true} if this thread has been interrupted; * {@code false} otherwise. * @see #interrupted() * @revised 6.0 */ public boolean isInterrupted() { return isInterrupted(false); }
/** * Tests if some Thread has been interrupted. The interrupted state * is reset or not based on the value of ClearInterrupted that is * passed. */ @HotSpotIntrinsicCandidate private native boolean isInterrupted(boolean ClearInterrupted);
静态方法interrupted()检查中断状态时,中断状态会被清零(置为false)。
调用方式如下:
源代码的定义如下:
/** * 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). * * <p>A thread interruption ignored because a thread was not alive * at the time of the interrupt will be reflected by this method * returning false. * * @return {@code true} if the current thread has been interrupted; * {@code false} otherwise. * @see #isInterrupted() * @revised 6.0 */ public static boolean interrupted() { return currentThread().isInterrupted(true); }
/** * Tests if some Thread has been interrupted. The interrupted state * is reset or not based on the value of ClearInterrupted that is * passed. */ @HotSpotIntrinsicCandidate private native boolean isInterrupted(boolean ClearInterrupted);
小结:
从上述源代码的定义可以看到,isInterrupted()和interrupted() 调用了同一个native方法,但是传递的参数不一样。
示例
例一
在下面的例子中,主线程通过调用t.interrupt()方法将线程t的中断状态设置为true,线程t可以在合适的时候调用interrupted()方法或isInterrupted()方法来检测其中断状态并做相应处理:
package com.test; public class ThreadTest extends Thread { public void run() { while (true) { if (Thread.interrupted()) { System.out.println("Someone interrupted me."); break; } else { System.out.println("Going..."); } long now = System.currentTimeMillis(); while (System.currentTimeMillis() - now < 1000) { //让循环持续一段时间,打印的输出语句会少一些 } } } public static void main(String[] args) throws InterruptedException { ThreadTest t = new ThreadTest(); t.start(); Thread.sleep(3000); t.interrupt(); } }
结果如下:
Going...
Going...
Going...
Someone interrupted me.
结论:
(1)对于非阻塞中的线程, 只是改变了中断状态, 即Thread.isInterrupted()将返回true;
(2)对于可取消的阻塞状态中的线程, 比如等待在Thread.sleep(), Object.wait(), Thread.join(),这些函数上的线程, 这个线程收到中断信号后, 会抛出InterruptedException, 同时会把中断状态置回为false.
例二
下面这段程序会使得阻塞在Thread.join()方法上的主线程在收到中断信号后结束:
package com.test; public class ThreadTest extends Thread { private Thread parent; public ThreadTest(Thread parent){ this.parent = parent; } public void run() { while (true) { System.out.println("sub thread is running..."); long now = System.currentTimeMillis(); while (System.currentTimeMillis() - now < 2000) { //让循环持续一段时间,打印的输出语句会少一些 } parent.interrupt(); } } public static void main(String[] args){ ThreadTest t = new ThreadTest(Thread.currentThread()); t.start(); try { t.join(); } catch (InterruptedException e) { System.out.println("Parent thread will die..."); } } }
结果如下:
sub thread is running...
Parent thread will die...
sub thread is running...
sub thread is running...
sub thread is running...
sub thread is running...
从结果可以看出,线程t发出中断请求后主线程结束(此时线程t仍在运行)