线程中断理解

xiaoxiao2021-02-28  88

无法中断的线程

package objective1.action2; public class InterruptHandler { public static void main(String[] args) { Runnable runnable = new InterruptRunner(); Thread thread = new Thread(runnable); thread.start(); thread.interrupt(); } } class InterruptRunner implements Runnable { @Override public void run() { int i = 0; while (true) { System.out.println("i=" + i++); } } }

该例子尝试使用用interrupt中断线程,但interrupt方法并不像break方法一样,马上停止循环,而是持续对i增加,不会停止。

中断可以理解为线程的一个标识位属性,它表示一个运行中的线程是否被其他线程进行了中断操作。中断好比其他线程对该线程打了个招呼,其他线程通过调用该线程的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(); }

从上面源码中也可与看出,interrupt只是在当前线程中打了个停止标志。 那么如何才能停止线程呢? 可以在该线程中观察中断标志状态,如果中断标志状态显示中断,就可以在该线程中执行中断。

判断线程中断的状态

Thread提供了两种方法判断线程中断状态。

public static boolean interrupted() public boolean isInterrupted()

两个方法有什么区别呢? interrupted方法: 测试当前线程是否已经是中断状态,并清除标志位 isInterrupted方法:测试当前线程是否已经是中断状态,不清除标志位

isInterrupted()方法 public class InterruptHandler2 { public static void main(String[] args) { Thread thread = new InterruptThread(); thread.start(); thread.interrupt(); } } class InterruptThread extends Thread { @Override public void run() { System.out.println("停止状态1:" + Thread.currentThread().isInterrupted()); System.out.println("停止状态2:" + Thread.currentThread().isInterrupted()); System.out.println("停止状态3:" + Thread.currentThread().isInterrupted()); } } 停止状态1true 停止状态2true 停止状态3true

可以看出isInterrupted()判断状态后,再次判断中断状态仍然是true,没有清除中断标志位。

interrupted方法 public class InterruptHandler2 { public static void main(String[] args) { Thread thread = new InterruptThread1(); thread.start(); thread.interrupt(); } } class InterruptThread1 extends Thread { @Override public void run() { System.out.println("停止状态1:" + Thread.interrupted()); System.out.println("停止状态2:" + Thread.interrupted()); System.out.println("停止状态3:" + Thread.interrupted()); } } 停止状态1true 停止状态2false 停止状态3false

可以看出interrupted()判断状态后,再次判断中断状态全是false,说明将标志位恢复了。

源码分析

观察Thread源码,发现这两个方法最终都是调用 isInterrupted(boolean ClearInterrupted),不同的只是interrupted()默认将清除中断标志位设成true.

public boolean isInterrupted() { return isInterrupted(false); } public static boolean interrupted() { return currentThread().isInterrupted(true); } private native boolean isInterrupted(boolean ClearInterrupted);

停止线程的方法

使用异常停止

使用break停止

判断中断标志位,当标志位被置为中断时,使用break中断。虽然中断了while循环但是,还是继续往下执行了,也就是说线程没有立即停止。

public class InterruptHandler { public static void main(String[] args) { System.out.println("start"); Runnable runnable = new InterruptRunner(); Thread thread = new Thread(runnable); thread.start(); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); System.out.println("end"); } } class InterruptRunner implements Runnable { @Override public void run() { int i = 0; while (true) { if (Thread.currentThread().isInterrupted()) { System.out.println("已经是中断状态了,我要退出了"); break; } System.out.println("我还没中断 i=" + i++); } System.out.println("我在while下面!我被执行说明break后代码继续运行,线程没有立即停止"); } } .... 我还没中断 i=3 end 已经是中断状态了,我要退出了 我在while下面!我被执行说明break后代码继续运行,线程没有立即停止

使用在sleep中catch异常停止

public class InterruptHandler { public static void main(String[] args) { System.out.println("start"); Runnable runnable = new InterruptRunner(); Thread thread = new Thread(runnable); thread.start(); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); System.out.println("end"); } } class InterruptRunner implements Runnable { @Override public void run() { int i = 0; try { while (true) { if (Thread.currentThread().isInterrupted()) { System.out.println("已经是中断状态了,我要退出了"); Thread.sleep(100); } System.out.println("我还没中断 i=" + i++); } } catch (InterruptedException e) { System.out.println("中断标志" + Thread.currentThread().isInterrupted()); System.out.println("进入" + Thread.currentThread().getName() + "的exception方法,然后中断"); System.out.println(e); Thread.currentThread().interrupt(); } } } 我还没中断 i=19 end 已经是中断状态了,我要退出了 catch exception后中断标志false 进入Thread-0exception方法,然后中断 java.lang.InterruptedException: sleep interrupted

可以看出在线程sleep时候,存在中断操作会抛出InterruptedException ,并且将清除中断标志位停止状态。而这时若catch住异常,并对线程执行interrupt操作,就可以达到中断线程的效果。

Q:那么为什么在线程sleep的时候,执行中断操作(或中断时候执行sleep)会抛出异常呢? 当thread被阻塞的时候,比如被Object.wait,Thread.join和Thread.sleep三种方法之一阻塞时。调用它的interrput()方法。 可想而知,没有占用CPU运行的线程是不可能给自己的中断状态置位的。这就会产生一个InterruptedException异常。

使用抛出异常在外面catch停止

public class InterruptHandler { public static void main(String[] args) { System.out.println("start"); Runnable runnable = new InterruptRunner(); Thread thread = new Thread(runnable); thread.start(); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); System.out.println("end"); } } class InterruptRunner implements Runnable { @Override public void run() { int i = 0; try { while (true) { if (Thread.currentThread().isInterrupted()) { System.out.println("已经是中断状态了,我要退出了"); throw new InterruptedException(); } System.out.println("我还没中断 i=" + i++); } } catch (InterruptedException e) { System.out.println("中断标志" + Thread.currentThread().isInterrupted()); System.out.println("进入" + Thread.currentThread().getName() + "的exception方法,然后中断"); System.out.println(e); } } } 我还没中断 i=57 end 已经是中断状态了,我要退出了 中断标志true 进入Thread-0exception方法,然后中断 java.lang.InterruptedException

如上例子判断中断标志位为true时,立即将异常抛出,并在外层处理达到线程停止。这样做的好处是,还可以将异常往外抛,使线程停止的事件得以传播。

使用return的方法停止

public class InterruptHandler { public static void main(String[] args) { System.out.println("start"); Runnable runnable = new InterruptRunner(); Thread thread = new Thread(runnable); thread.start(); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); System.out.println("end"); } } class InterruptRunner implements Runnable { @Override public void run() { int i = 0; while (true) { if (Thread.currentThread().isInterrupted()) { System.out.println("已经是中断状态了,我要退出了"); return; } System.out.println("我还没中断 i=" + i++); } } } start 我还没中断 i=0 end 已经是中断状态了,我要退出了

可以看出,其实和用异常方法停止线程没有本质区别,都是在判断中断标志位被设置为true时,进行退出操作。

使用过期的stop方法停止

stop()方法在终结一个线程时不会保证线程的资源正常释放,通常是没有给予线程完成资源释放工作的机会,因此会导致程序可能工作在不确定状态下。不建议使用。

转载请注明原文地址: https://www.6miu.com/read-78260.html

最新回复(0)