通過一個變量控制線程中斷
代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package com.itsoku.chat05; import java.util.concurrent.TimeUnit; /** * 微信公眾號:路人甲Java,專注于java技術分享(帶你玩轉 爬蟲、分布式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注! */ public class Demo1 { public volatile static boolean exit = false ; public static class T extends Thread { @Override public void run() { while ( true ) { //循環處理業務 if (exit) { break ; } } } } public static void setExit() { exit = true ; } public static void main(String[] args) throws InterruptedException { T t = new T(); t.start(); TimeUnit.SECONDS.sleep( 3 ); setExit(); } } |
代碼中啟動了一個線程,線程的run方法中有個死循環,內部通過exit變量的值來控制是否退出。 TimeUnit.SECONDS.sleep(3);讓主線程休眠3秒,此處為什么使用TimeUnit?TimeUnit使用更方便一些,能夠很清晰的控制休眠時間,底層還是轉換為Thread.sleep實現的。程序有個重點:volatile關鍵字,exit變量必須通過這個修飾,如果把這個去掉,程序無法正常退出。volatile控制了變量在多線程中的可見性,關于volatile前面的文章中有介紹,此處就不再說了。
通過線程自帶的中斷標志控制
示例代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package com.itsoku.chat05; import java.util.concurrent.TimeUnit; /** * 微信公眾號:路人甲Java,專注于java技術分享(帶你玩轉 爬蟲、分布式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注! */ public class Demo2 { public static class T extends Thread { @Override public void run() { while ( true ) { //循環處理業務 if ( this .isInterrupted()) { break ; } } } } public static void main(String[] args) throws InterruptedException { T t = new T(); t.start(); TimeUnit.SECONDS.sleep( 3 ); t.interrupt(); } } |
運行上面的程序,程序可以正常結束。線程內部有個中斷標志,當調用線程的interrupt()實例方法之后,線程的中斷標志會被置為true,可以通過線程的實例方法isInterrupted()獲取線程的中斷標志。
線程阻塞狀態中如何中斷?
示例代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.itsoku.chat05; import java.util.concurrent.TimeUnit; /** * 微信公眾號:路人甲Java,專注于java技術分享(帶你玩轉 爬蟲、分布式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注! */ public class Demo3 { public static class T extends Thread { @Override public void run() { while ( true ) { //循環處理業務 //下面模擬阻塞代碼 try { TimeUnit.SECONDS.sleep( 1000 ); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws InterruptedException { T t = new T(); t.start(); } } |
運行上面代碼,發現程序無法結束。
在此先補充幾點知識:
1.調用線程的interrupt()實例方法,線程的中斷標志會被置為true
2.當線程處于阻塞狀態時,調用線程的interrupt()實例方法,線程內部會觸發InterruptedException異常,并且會清除線程內部的中斷標志(即將中斷標志置為false)
那么上面代碼可以調用線程的interrupt()方法來引發InterruptedException異常,來中斷sleep方法導致的阻塞,調整一下代碼,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package com.itsoku.chat05; import java.util.concurrent.TimeUnit; /** * 微信公眾號:路人甲Java,專注于java技術分享(帶你玩轉 爬蟲、分布式事務、異步消息服務、任務調度、分庫分表、大數據等),喜歡請關注! */ public class Demo3 { public static class T extends Thread { @Override public void run() { while ( true ) { //循環處理業務 //下面模擬阻塞代碼 try { TimeUnit.SECONDS.sleep( 1000 ); } catch (InterruptedException e) { e.printStackTrace(); this .interrupt(); } if ( this .isInterrupted()) { break ; } } } } public static void main(String[] args) throws InterruptedException { T t = new T(); t.start(); TimeUnit.SECONDS.sleep( 3 ); t.interrupt(); } } |
運行結果:
1
2
3
4
5
|
java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at java.lang.Thread.sleep(Thread.java: 340 ) at java.util.concurrent.TimeUnit.sleep(TimeUnit.java: 386 ) at com.itsoku.chat05.Demo3$T.run(Demo3.java: 17 ) |
程序可以正常結束了,分析一下上面代碼,注意幾點:
1.main方法中調用了t.interrupt()方法,此時線程t內部的中斷標志會置為true
2.然后會觸發run()方法內部的InterruptedException異常,所以運行結果中有異常輸出,上面說了,當觸發InterruptedException
異常時候,線程內部的中斷標志又會被清除(變為false),所以在catch中又調用了this.interrupt();一次,將中斷標志置為false
3.run()方法中通過this.isInterrupted()來獲取線程的中斷標志,退出循環(break)
總結
當一個線程處于被阻塞狀態或者試圖執行一個阻塞操作時,可以使用 Thread.interrupt()方式中斷該線程,注意此時將會拋出一個InterruptedException的異常,同時中斷狀態將會被復位(由中斷狀態改為非中斷狀態)
內部有循環體,可以通過一個變量來作為一個信號控制線程是否中斷,注意變量需要volatile修飾
文中的幾種方式可以結合起來靈活使用控制線程的中斷
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注服務器之家的更多內容!
原文鏈接:https://itsoku.blog.csdn.net/article/details/100036221