一 中斷線程
1.1 中斷概念
1.在java中,沒有提供一種立即停止一條線程。但卻給了停止線程的協商機制-中斷。
中斷是一種協商機制。中斷的過程完全需要程序員自己實現。也即,如果要中斷一個線程,你需要手動調用該線程的interrupt()方法,該方法也僅僅是將線程對象中的中斷標識設置成true;接著需要自己在方法中手動判斷當前線程的標識位,如果為true,則中斷線程。false標識未中斷。
2.一個線程不應該由其他線程中斷或者停止,而是有該線程自己自行停止,自己決定命運。
stop(),suspend,resume方法都已經廢棄。
1.2?interrupt和isinterrupted和interrupted的作用
1.public void interrupt(): 實例方法,僅僅是設置線程中斷狀態為true,發起一個協商而不會立刻停止線程。
2.public static boolean interrupted;靜態方法,判斷當前線程是否中斷并清除當前線程的中斷狀態。做兩件事:
a)返回當前線程的中斷狀態,測試當前線程是否已經中斷。
b)將當前線程的中斷狀態清零并重新設置為true,清除線程的中斷狀態。
3.public boolean isinterrupted():實例方法判斷當前線程是不是中斷,檢測中斷標志位。
1.3?interrupt的使用情況分析
當對一個線程,調用interrupt()時:
1.如果線程處于正常活動狀態,那么會將該線程的中斷標志設置為true,僅此而已。
被設置中斷標志的線程將繼續正常運行,不受影響。
interrupt()并不能真正中斷線程,需要被調用的線程自己進行配合才行。
2.如果線程處于被阻塞狀態(sleep,wait,join等狀態),在別的線程中調用當前線程對象的interrupt方法,那么線程將立即退出被阻塞的狀態,并拋出一個interruptedException異常。?
二 中斷線程方式
2.1 方式1 通過volatile變量
package com.ljf.thread.interrupt;import java.util.concurrent.atomic.AtomicBoolean;/*** @ClassName: Zhongduan2* @Description: TODO* @Author: admin* @Date: 2024/03/02?17:43:01?* @Version: V1.0**/
public class Zhongduan2 {public static volatile boolean flag=false;static AtomicBoolean atomicBoolean = new AtomicBoolean(false);public static void main(String[] args) throws InterruptedException {Thread t1= new Thread(new Runnable() {@Overridepublic void run() {while(true){if(flag){// if(atomicBoolean.get()){System.out.println("===================開始中斷"+Thread.currentThread().getId());break;}else{System.out.println("循環中:"+Thread.currentThread().getId());}}}});t1.start();//主線程先休眠2秒Thread.sleep(5000);new Thread(new Runnable() {@Overridepublic void run() {flag=true;atomicBoolean.set(true);}}).start();}}
2.2? 方式2 通過atomicboolean 原子類
public static volatile boolean flag=false;static AtomicBoolean atomicBoolean = new AtomicBoolean(false);public static void main(String[] args) throws InterruptedException {Thread t1= new Thread(new Runnable() {@Overridepublic void run() {while(true){// if(flag){if(atomicBoolean.get()){System.out.println("===================開始中斷"+Thread.currentThread().getId());break;}else{System.out.println("循環中:"+Thread.currentThread().getId());}}}});t1.start();//主線程先休眠2秒Thread.sleep(5000);new Thread(new Runnable() {@Overridepublic void run() {flag=true;atomicBoolean.set(true);}}).start();}
2.3 方式3 通過interrupt+isinterrupted組合判斷
package com.ljf.thread.interrupt;/*** @ClassName: Zhongduan* @Description: TODO* @Author: admin* @Date: 2024/03/02?17:34:59?* @Version: V1.0**/
public class Zhongduan {public static volatile boolean flag=false;public static void main(String[] args) throws InterruptedException {Thread t1= new Thread(new Runnable() {@Overridepublic void run() {while(true){if(Thread.currentThread().isInterrupted()){System.out.println("===================開始中斷"+Thread.currentThread().getId());break;}else{System.out.println("循環中:"+Thread.currentThread().getId());}}}});t1.start();//主線程先休眠2秒Thread.sleep(5000);new Thread(new Runnable() {@Overridepublic void run() {t1.interrupt();}}).start();}
}
三 中斷線程方式的情況分析
3.1 情況1
如果線程處于被阻塞狀態(sleep,wait,join等狀態),在別的線程中調用當前線程對象的interrupt方法,那么線程將立即退出被阻塞的狀態,并拋出一個interruptedException異常。
public static void main(String[] args){//實例方法interrupt()僅僅是設置線程的中斷狀態位設置為true,不會停止線程Thread t1 = new Thread(() -> {for (int i = 1; i <=300; i++){System.out.println("-----: "+i);}System.out.println("t1線程調用interrupt()后的的中斷標識02:"+Thread.currentThread().isInterrupted());}, "t1");t1.start();System.out.println("t1線程默認的中斷標識:"+t1.isInterrupted());//false//暫停毫秒try { TimeUnit.MILLISECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }t1.interrupt();//trueSystem.out.println("t1線程調用interrupt()后的的中斷標識01:"+t1.isInterrupted());//truetry { TimeUnit.MILLISECONDS.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println("t1線程調用interrupt()后的的中斷標識03:"+t1.isInterrupted());//---false中斷不活動的線程不會產生任何影響。}
線程t1執行300次后,已經不存在,2秒后查看t1線程的狀態為false。
3.2 情況2
1.代碼
public class InterruptDemo3
{public static void main(String[] args){Thread t1 = new Thread(() -> {while (true){if(Thread.currentThread().isInterrupted()){System.out.println(Thread.currentThread().getName()+"\t " +"中斷標志位:"+Thread.currentThread().isInterrupted()+" 程序停止");break;}try {Thread.sleep(200);} catch (InterruptedException e) {Thread.currentThread().interrupt();//為什么要在異常處,再調用一次??e.printStackTrace();}System.out.println("-----hello InterruptDemo3");}}, "t1");t1.start();//暫停幾秒鐘線程try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }new Thread(() -> t1.interrupt(),"t2").start();}
}
問題:報異常,程序沒有停止
2.分析原因
* 1 中斷標志位,默認false * 2 t2 ----> t1發出了中斷協商,t2調用t1.interrupt(),中斷標志位true * 3 中斷標志位true,正常情況,程序停止,^_^ * 4 中斷標志位true,執行sleep 后發生異常情況,InterruptedException,將會把中斷狀態將被清除,并且將收到InterruptedException 。中斷標志位false * 導致無限循環 * * 5 在catch塊中,需要再次給中斷標志位設置為true,2次調用停止程序才OK
3.結論
3.3?情況3 關閉線程
https://blog.51cto.com/u_13316945/5832262
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);Future future = fixedThreadPool.submit(new Runnable() { @Override public void run() {
new Runnable() {@Overridepublic void run() {/** 確保線程不斷執行不斷刷新界面*/while (true&&(!Thread.currentThread().isInterrupted())) {try {Log.i("tag","線程運行中"+Thread.currentThread().getId());// 每執行一次暫停40毫秒//當sleep方法拋出InterruptedException 中斷狀態也會被清掉Thread.sleep(40);} catch (InterruptedException e) {e.printStackTrace();//如果拋出異常則再次設置中斷請求Thread.currentThread().interrupt();}}}}
);
//觸發條件設置中斷
future.cancel(true);