自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊 Java 中的中斷機制

開發(fā) 后端
在Java中,用于終止一個正在運行中的線程,并非調(diào)用stop方法,而是自行設(shè)置一個標(biāo)志位,在安全點檢測標(biāo)志位,決定是否退出,但也可能會因為線程被掛起,無法走到標(biāo)志位。

[[439899]]

在Java中,用于終止一個正在運行中的線程,并非調(diào)用stop方法,而是自行設(shè)置一個標(biāo)志位,在安全點檢測標(biāo)志位,決定是否退出,但也可能會因為線程被掛起,無法走到標(biāo)志位。因此,Java線程提供了中斷機制,Thread類提供了中斷線程執(zhí)行的調(diào)用方法:interrupt,用于中斷因線程掛起的等待,調(diào)用interrupt方法后,線程會被喚醒,待下次cpu調(diào)度就會繼續(xù)執(zhí)行中斷后的代碼 。

我們經(jīng)常會調(diào)用Thread#sleep、Object#wait、Queue#poll等方法,并要求我們處理InterruptedException異常。 那么,拋出InterruptedException后,線程會終止嗎?

如果不捕獲InterruptedException,那么線程就會因為異常終止,是因為異常終止,并不是因為被中斷。如果捕獲了InterruptedException,那么線程就不會終止。

中斷,其實只是jvm用于喚醒因鎖競爭、I/O操作、休眠等待被掛起的線程,并設(shè)置一個中斷標(biāo)志,我們可以利用這個標(biāo)志去做一些處理。比如,當(dāng)我們發(fā)送消息給遠程服務(wù)器,并休眠等待結(jié)果時,如果線程被喚醒,并設(shè)置了中斷標(biāo)志,此時我們可以知道,并非等到結(jié)果被喚醒的,而是被中斷喚醒的,可以決定是繼續(xù)等待結(jié)果,還是放棄等待。

xxl-job提供取消任務(wù)操作,而任何運行中的線程,都只能利用中斷機制去結(jié)束線程任務(wù),所以我們想要任務(wù)支持被取消,那么在寫定時任務(wù)時,一定要考慮清楚,是不是應(yīng)該捕獲InterruptedException,如何利用中斷標(biāo)志結(jié)束任務(wù),否則將會導(dǎo)致任務(wù)無法被取消。

我們來看個案例:

  1. @Test 
  2. public void test() { 
  3.     ExecutorService executorService = Executors.newSingleThreadExecutor(); 
  4.     Future<?> future = executorService.submit(() -> { 
  5.         while (true) { 
  6.             System.out.println( "rung....." ); 
  7.             ThreadUtils.sleep(1000); 
  8.         } 
  9.     }); 
  10.     ThreadUtils.sleep(1000); 
  11.     future.cancel(true); 
  12.     try { 
  13.         future.get(); 
  14.     } catch (InterruptedException | CancellationException | ExecutionException e) { 
  15.         e.printStackTrace(); 
  16.     } 
  17.     ThreadUtils.sleep(1000 * 60); 

此案例創(chuàng)建了只有一個線程的線程池,提交了一個死循序任務(wù),該任務(wù)只調(diào)用ThreadUtils.sleep方法進入休眠。平常我們調(diào)用Thread.sleep方法都要求是否捕獲中斷異常,很多時候我們都會嫌棄麻煩,就用一個工具類提供sleep方法,然后將中斷異常捕獲,如ThreadUtils:

  1. public class ThreadUtils { 
  2.     public static void sleep(long millis) { 
  3.         try { 
  4.             Thread.sleep(millis); 
  5.         } catch (InterruptedException ignored) { 
  6.         } 
  7.     } 

此案例中,由于我們捕獲了中斷異常,因此這會導(dǎo)致任務(wù)并不會被終止,只是當(dāng)我們調(diào)用future的get方法時會拋出CancellationException異常,如下圖所示。

任務(wù)依然在運行中......

因此,在實際開發(fā)中,如果我們開發(fā)的Job也是如此,將會導(dǎo)致Job無法被中斷取消,直至Job執(zhí)行完成或者重啟。在開發(fā)Job時,應(yīng)當(dāng)合理考慮是否要捕獲中斷異常。

如果我們希望案例中的任務(wù)能夠被終止,我們可以這樣處理:

  1. @Test 
  2. public void test() { 
  3.     ExecutorService executorService = Executors.newSingleThreadExecutor(); 
  4.     Future<?> future = executorService.submit(() -> { 
  5.         while (true) { 
  6.             System.out.println( "rung....." ); 
  7.             try { 
  8.                 Thread.sleep(1000); 
  9.             } catch (InterruptedException ex) { 
  10.                 System.err.println( "interrupted" ); 
  11.                 return; // 退出死循環(huán) 
  12.             } 
  13.         } 
  14.     }); 
  15.     ThreadUtils.sleep(1000); 
  16.     future.cancel(true); 
  17.     try { 
  18.         future.get(); 
  19.     } catch (InterruptedException | CancellationException | ExecutionException e) { 
  20.         e.printStackTrace(); 
  21.     } 
  22.     ThreadUtils.sleep(1000 * 60); 

關(guān)于Thread的interrupt方法,注釋描述的大致意思如下:

  • 如果被中斷的線程,當(dāng)前是調(diào)用Object#wait、Thread#join、Thread#sleep方法,將收到InterruptedException,并且會清除中斷標(biāo)志;
  • 如果此線程在I/O操作中(指java nio)被阻塞,調(diào)用interrupt方法通道將被關(guān)閉,線程將收到一個ClosedByInterruptException,并且會設(shè)置中斷標(biāo)志;
  • ....

怎么理解中斷標(biāo)志呢?

“如果被中斷的線程,當(dāng)前是調(diào)用Object#wait、Thread#join、Thread#sleep方法,將收到InterruptedException,并且會清除中斷標(biāo)志”,案例中的代碼正好符合這點,如果我們將案例代碼改為如下:

  1. @Test 
  2. public void test() { 
  3.     ExecutorService executorService = Executors.newSingleThreadExecutor(); 
  4.     Future<?> future = executorService.submit(() -> { 
  5.         while (!Thread.interrupted()) { 
  6.             System.out.println( "rung....." ); 
  7.             try { 
  8.                 Thread.sleep(1000); 
  9.             } catch (InterruptedException ex) { 
  10.                 System.err.println( "interrupted" ); 
  11.             } 
  12.         } 
  13.     }); 
  14.     ThreadUtils.sleep(1000); 
  15.     future.cancel(true); 
  16.     try { 
  17.         future.get(); 
  18.     } catch (InterruptedException | CancellationException | ExecutionException e) { 
  19.         e.printStackTrace(); 
  20.     } 
  21.     ThreadUtils.sleep(1000 * 60); 

執(zhí)行這段代碼你會發(fā)現(xiàn),死循環(huán)根本沒有退出,正是因為Thread#sleep方法被中斷,JVM并不會設(shè)置中斷標(biāo)志,只是拋出InterruptedException異常。

其它情況下,JVM只會設(shè)置中斷標(biāo)志,并不會拋出InterruptedException。如果我們不處理中斷信號,那么中斷信號并不會影響程序的繼續(xù)執(zhí)行。

  1. @Test 
  2. public void test2() { 
  3.     ExecutorService executorService = Executors.newSingleThreadExecutor(); 
  4.     Future<?> future = executorService.submit(() -> { 
  5.         int number = 0; 
  6.         while (!Thread.interrupted()) { 
  7.             number++; 
  8.         } 
  9.         System.out.println(number); 
  10.     }); 
  11.     ThreadUtils.sleep(1000); 
  12.     future.cancel(true); 
  13.     try { 
  14.         future.get(); 
  15.     } catch (InterruptedException | CancellationException | ExecutionException e) { 
  16.         e.printStackTrace(); 
  17.     } 
  18.     ThreadUtils.sleep(1000 * 60); 

 

此案例并沒有I/O操作導(dǎo)致的阻塞,因為調(diào)用中斷方法后,線程只是設(shè)置了中斷標(biāo)志,我們用中斷標(biāo)志作為循序的退出條件,運行此案例,我們將看到,線程中斷后,任務(wù)終止。反之,如果我們不處理中斷標(biāo)志,那么就等著IDEA進程卡掉吧。

 

責(zé)任編輯:武曉燕 來源: Java藝術(shù)
相關(guān)推薦

2020-11-20 07:51:02

JavaSPI機制

2015-08-03 09:54:26

Java線程Java

2024-02-27 08:05:32

Flink分區(qū)機制數(shù)據(jù)傳輸

2022-05-06 08:26:32

JavaSPI機制

2023-02-24 16:46:25

Glide緩存機制

2009-07-23 14:08:46

Windows Emb

2025-01-14 10:09:43

硬中斷Linux系統(tǒng)

2022-04-02 08:14:02

JavaThreadLoca數(shù)據(jù)

2025-03-27 02:00:00

SPIJava接口

2021-09-26 05:06:04

Node.js模塊機制

2024-06-11 09:22:51

2021-03-09 08:01:27

CPUarm64寄存器

2020-07-02 22:42:18

Java異常編程

2024-05-11 08:31:20

中斷機制插隊機制React

2022-03-11 20:46:01

機制命令kerberos

2021-02-05 08:41:44

STM32網(wǎng)絡(luò)中斷

2021-02-03 15:12:08

java內(nèi)存溢出

2021-03-28 08:32:58

Java

2021-11-17 08:11:35

MySQL

2024-04-26 00:00:00

Rust檢查器代碼
點贊
收藏

51CTO技術(shù)棧公眾號