interrupt()的字面意思是中断一个线程,那么它是怎么使用来达到中断当前线程的呢?我们来看几个例子。
一、终止处于“阻塞状态”的线程
通过中断方式终止处于阻塞状态的线程,当线程由于被调用了sleep(),wait(),join()等方法而进入阻塞状态,此时调用线程的interrupt()将线程的中断标记为true。由于处于阻塞状态,中断标记会被清除,同时产生一个InterruptedException
异常,将InterruptedException
放在适当的位置就能终止线程
@Overridepublic void run() { try { while (true) { // 执行任务... } } catch (InterruptedException ie) { // 由于产生InterruptedException异常,退出while(true)循环,线程终止! } }
说明:
在
while(true)
中不断的执行任务,当线程处于阻塞状态时,调用线程的interrupt()
方法会产生InterruptedException
中断,中断的捕获在while(true)
之外,这样就退出了while(true)
循环。
对InterruptException
的捕获一定要放在while(true)
循环体的外面,这样产生异常时就退出了while(true)
循环,否则,InterruptException
在while(true)
循环体之外,就需要额外的添加退出处理,形式如下:
@Overridepublic void run() { while (true) { try { // 执行任务... } catch (InterruptedException ie) { // InterruptedException在while(true)循环体内。 // 当线程产生了InterruptedException异常时,while(true)仍能继续运行!需要手动退出 break; } } }
上面的
InterruptedException
异常的捕获是在while(true)
中,当产生异常被catch
时,仍然在while(true)
循环体内,要退出while(true)
循环体,需要额外的执行操作。
二、终止处于运行状态的线程
通过标记方式终止处于运行状态的线程,其中,包括“中断标记”和“额外添加标记”
(1)通过“中断标记”终止线程,形式如下:
@Overridepublic void run() { while (!isInterrupted()) { // 执行任务... } }
说明:
isInterrupted()
是判断线程的中断标记是不是为true,当前线程处于运行状态,并且我们需要终止它时,可以调用线程的interrupt()
方法,使用线程的中断标记为true,即isInterrupted()
会返回true
,此时,就会退出while
循环。interrupt()
并不会终止处于“运行状态”的线程,它会将线程的中断标记设为true
(2)通过“额外添加标记”,形式如下:
rivate volatile boolean flag= true; protected void stopTask() { flag = false; }@Overridepublic void run() { while (flag) { // 执行任务... } }
说明:
线程中有一个
flag
标记,它的默认值是true
,并且我们提供stopTask()
来设置flag
标记,当我们需要终止该线程时,调用该线程的stopTask()
方法就可以让线程退出while循环
。其中将flag定义为volatile
类型,保证flag
的可见性,其他线程通过stopTask()
修改了flag
之后,本线程能看到修改后的flag
的值。
综合终止处于“阻塞状态”和“运行状态”的终止方式。
@Overridepublic void run() { try { // 1. isInterrupted()保证,只要中断标记为true就终止线程。 while (!isInterrupted()) { // 执行任务... } } catch (InterruptedException ie) { // 2. InterruptedException异常保证,当InterruptedException异常产生时,线程被终止。 } }
三、终止线程的示例
interrupt()
常常被用来终止“阻塞状态”线程,参考示例:
class MyThread extends Thread { public MyThread(String name) { super(name); } @Override public void run() { try { int i=0; while (!isInterrupted()) { System.out.println("thread is running"); Thread.sleep(100); // 休眠100ms i++; System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i); } } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException."); } } }public class Hello { public static void main(String[] args) { try { Thread t1 = new MyThread("t1"); // 新建“线程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is new."); t1.start(); // 启动“线程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is started."); // 主线程休眠300ms,然后主线程给t1发“中断”指令。 System.out.println("MainThread sleep"); Thread.sleep(300); System.out.println("Thread interrupt"); t1.interrupt(); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted."); // 主线程休眠300ms,然后查看t1的状态。 System.out.println("MainThread sleep"); Thread.sleep(300); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now."); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果:
t1 (NEW) is new. t1 (RUNNABLE) is started. MainThread sleep thread is running t1 (RUNNABLE) loop 1thread is running t1 (RUNNABLE) loop 2thread is running t1 (RUNNABLE) loop 3thread is running Thread interrupt t1 (TIMED_WAITING) is interrupted. MainThread sleep t1 (RUNNABLE) catch InterruptedException. t1 (TERMINATED) is interrupted now.
结果说明:
(1)主线程main中会通过new MyThread("t1")创建线程t1,之后通过t1.start()启动线程t1
(2)t1启动之后,会不断的检查他的中断标记,如果中断标记为false,则休眠100ms
(3)t1休眠之后会切换到主线程main,主线程再次运行时,会执行t1.interrupt()中断线程t1。t1收到中断指令之后,会将t1的中断标志设置为false,而且会抛出InterruptedException
异常,在t1的run()方法中,是在循环体之外捕获的异常,因此循环被终止。
通过“额外添加标记”的方式终止“运行状态”的线程的示例:
class MyThread extends Thread { private volatile boolean flag= true; public void stopTask() { flag = false; } public MyThread(String name) { super(name); } @Override public void run() { synchronized(this) { try { int i=0; while (flag) { Thread.sleep(100); // 休眠100ms i++; System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i); } } catch (InterruptedException ie) { System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException."); } } } }public class Hello { public static void main(String[] args) { try { MyThread t1 = new MyThread("t1"); // 新建“线程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is new."); t1.start(); // 启动“线程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is started."); // 主线程休眠300ms,然后主线程给t1发“中断”指令。 Thread.sleep(300); System.out.println("stopTask"); t1.stopTask(); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted."); // 主线程休眠300ms,然后查看t1的状态。 Thread.sleep(300); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now."); } catch (InterruptedException e) { e.printStackTrace(); } } }
interrupted()
和isInterrupted()
都能够用于检测对象的“中断标记”,区别是interrupted()
除了返回中断标记外,它还会清除中断标记(即将中断标记设为false),而isInterrupted()
仅仅返回中断标记,关于这两个方法的详细解释请看后续文章。
作者:激情的狼王
链接:https://www.jianshu.com/p/0eaa6597c287