靜態(tài)方法 Thread.interrupted()
實(shí)例方法 Thread.currentThread().isInterrupted()
這2個(gè)方法會(huì)返回線程的中斷狀態(tài),并把中斷狀態(tài)重置蹬挤!也就是說,調(diào)用這個(gè)方法之后祥绞,線程就不再是中斷狀態(tài)了创译,就可以開始新一輪的運(yùn)行了。
實(shí)例方法 Thread.currentThread().interrupt()
有一個(gè)運(yùn)行中的線程 t堤魁,在另一個(gè)線程中調(diào)用了 t.interrupt() 方法時(shí)蜜暑,t 線程的中斷狀態(tài)就被置為了true铐姚,當(dāng)然,t 線程并不會(huì)中斷運(yùn)行史煎,只是中斷狀態(tài)被置為了 true 谦屑。這個(gè)看似沒啥用驳糯,其實(shí)很有用。
interrupt() 的用途一:通過設(shè)置線程的中斷狀態(tài)可以喚醒阻塞/睡眠中的線程
當(dāng)線程 t 在 run 方法中調(diào)用了 Object 類 的 wait(), wait(long), or wait(long, int) 方法或者 Thread 類的 join(), join(long), join(long, int), sleep(long), sleep(long, int) 方法或者 ServerSocket.accept() 或者 DatagramSocket.receive() 等方法進(jìn)入阻塞狀態(tài)后氢橙,線程就會(huì)一直檢查中斷狀態(tài)酝枢,一旦發(fā)現(xiàn)被標(biāo)記為了中斷,就立即拋出 InterruptedException悍手,被喚醒帘睦;要想喚醒線程,就可以在另一個(gè)線程中調(diào)用 t.interrupt() 方法坦康,調(diào)用后竣付,這些阻塞方法就會(huì)拋出一個(gè) InterruptedException,這就達(dá)到了喚醒線程 t 的目的了滞欠,當(dāng)然古胆,拋出中斷異常的同時(shí),線程 t 的中斷狀態(tài)也會(huì)被置為 false筛璧,這個(gè)操作不是在 java 層實(shí)現(xiàn)的逸绎,因此 jdk 中看不到相關(guān)代碼,但是 interrupt() 的 API 注釋寫的很清楚夭谤。
-
結(jié)束線程的常見寫法(推薦)
class MyThread implements Runnable { public boolean stop; @Override public void run() { while(!stop) { // do something // 執(zhí)行完本輪任務(wù)棺牧,休眠1s,防止沒任務(wù)時(shí)線程空轉(zhuǎn)朗儒。 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
-
另一種寫法
class MyThread implements Runnable { @Override public void run() { while(!Thread.interrupted()) { // 注意這里颊乘,控制線程結(jié)束的條件和上面的代碼不一樣 // do something // 執(zhí)行完本輪任務(wù),休眠1s醉锄,防止沒任務(wù)時(shí)線程空轉(zhuǎn)乏悄。 try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread.interrupt(); // 將當(dāng)前線程標(biāo)記為中斷狀態(tài) } } } }
interrupt() 的用途二:通過設(shè)置線程的中斷狀態(tài)可以終止死鎖
synchronized關(guān)鍵字、ReentrantLock類的lock()恳不、lockInterruptibly()纲爸、tryLock()、tryLock(long, java.util.concurrent.TimeUnit) 都能獲取鎖妆够,但是 lockInterruptibly() 和 tryLock(long, java.util.concurrent.TimeUnit) 會(huì)在獲取鎖的過程中檢測(cè)線程中斷狀態(tài),一旦發(fā)現(xiàn)線程處于中斷狀態(tài)則立即拋出 InterruptedException 负蚊,另外三種方式則不檢測(cè)中斷神妹。
-
無法響應(yīng)中斷的線程,無法終止死鎖家妆。
public static void main(String[] args) { Object lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread( () -> { deadLock(lock1, lock2); // 先鎖1鸵荠,后鎖2 } ); Thread t2 = new Thread( () -> { deadLock(lock2, lock1); // 注意,順序相反 } ); t1.start(); t2.start(); t1.interrupt(); t2.interrupt(); System.out.println("發(fā)生了死鎖伤极,2個(gè)線程阻塞了蛹找,無法響應(yīng)中斷姨伤,因此,進(jìn)程無法結(jié)束庸疾。"); } private static void deadLock(Object lock1, Object lock2) { synchronized (lock1) { sleep(); synchronized(lock2){ System.out.println("..."); } } } private static void sleep() { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < 100) { } }
-
可以響應(yīng)中斷的線程乍楚,是可以終止死鎖的。
public static void main(String[] args) { ReentrantLock lock1 = new ReentrantLock(); ReentrantLock lock2 = new ReentrantLock(); Thread t1 = new Thread( () -> { deadLock(lock1, lock2); // 先鎖1届慈,后鎖2 } ); Thread t2 = new Thread( () -> { deadLock(lock2, lock1); // 注意徒溪,順序相反 } ); t1.start(); t2.start(); sleep(110); // 等 t1 和 t2 死鎖之后,再發(fā)中斷信號(hào)金顿。 t1.interrupt(); t2.interrupt(); System.out.println("發(fā)生了死鎖臊泌,但是阻塞住線程的方法可以響應(yīng)中斷,因此揍拆,進(jìn)程可以結(jié)束渠概。"); } private static void deadLock(ReentrantLock lock1, ReentrantLock lock2) { try { lock1.lockInterruptibly(); sleep(100); lock2.lockInterruptibly(); // 可以響應(yīng)中斷的函數(shù) } catch (InterruptedException e) { e.printStackTrace(); } } private static void sleep(int sleepTime) { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < sleepTime) { } }