欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中斷異常的正確處理方法

 更新時(shí)間:2019年09月10日 11:26:29   作者:java歐陽豐  
這篇文章主要給大家介紹了關(guān)于Java中斷異常的正確處理方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

處理InterruptedException

這個(gè)故事可能很熟悉:你正在寫一個(gè)測試程序,你需要暫停某個(gè)線程一段時(shí)間,所以你調(diào)用 Thread.sleep()。然后編譯器或 IDE 就會(huì)抱怨說 InterruptedException 沒有拋出聲明或捕獲。什么是 InterruptedException,你為什么要處理它?

最常見的響應(yīng) InterruptedException 做法是吞下它 - 捕獲它并且什么也不做(或者記錄它,也沒好多少) - 正如我們將在清單4中看到的那樣。不幸的是,這種方法拋棄了關(guān)于​​中斷發(fā)生的重要信息,這可能會(huì)損害應(yīng)用程序取消活動(dòng)或響應(yīng)及時(shí)關(guān)閉的能力。

阻塞方法

當(dāng)一個(gè)方法拋出 InterruptedException 時(shí),意味著幾件事情: 除了它可以拋出一個(gè)特定的檢查異常, 它還告訴你它是一種阻塞方法,它會(huì)嘗試解除阻塞并提前返回。

阻塞方法不同于僅需要很長時(shí)間才能運(yùn)行完成的普通方法。普通方法的完成僅取決于你要求它做多少事以及是否有足夠的計(jì)算資源(CPU周期和內(nèi)存)。另一方面,阻塞方法的完成還取決于某些外部事件,例如計(jì)時(shí)器到期,I/O 完成或另一個(gè)線程的操作(釋放鎖,設(shè)置標(biāo)志或放置任務(wù)到工作隊(duì)列)。普通方法可以在完成工作后立即結(jié)束,但阻塞方法不太好預(yù)測,因?yàn)樗鼈円蕾囉谕獠渴录?/p>

因?yàn)槿绻麄冋诘却肋h(yuǎn)不會(huì)在事件,發(fā)生堵塞的方法有可能永遠(yuǎn)不結(jié)束,常用在阻塞可取消的操作。對于長時(shí)間運(yùn)行的非阻塞方法,通常也是可以取消的??扇∠僮魇强梢栽谕ǔW孕型瓿芍皬耐獠繌?qiáng)制移動(dòng)到完成狀態(tài)的操作。 Thread提供的Thread.sleep() 和 Object.wait() 方法中斷機(jī)制是一種取消線程繼續(xù)阻塞的機(jī)制; 它允許一個(gè)線程請求另一個(gè)線程提前停止它正在做的事情。當(dāng)一個(gè)方法拋出時(shí) InterruptedException,它告訴你如果執(zhí)行方法的線程被中斷,它將嘗試停止它正在做的事情提前返回, 并通過拋出 InterruptedException 表明它的提早返回。表現(xiàn)良好的阻塞庫方法應(yīng)該響應(yīng)中斷并拋出 InterruptedException 異常, 以便它們可以應(yīng)用在可取消的活動(dòng)中而不會(huì)妨礙程序的響應(yīng)性。

線程中斷

每個(gè)線程都有一個(gè)與之關(guān)聯(lián)的布爾屬性,表示其中斷狀態(tài)。中斷狀態(tài)最初為假; 當(dāng)某個(gè)線程被其他線程通過調(diào)用中斷 Thread.interrupt() 時(shí), 會(huì)發(fā)生以下兩種情況之一: 如果該線程正在執(zhí)行低級(jí)別的中斷阻塞方法 Thread.sleep(),Thread.join()或 Object.wait()等,它取消阻塞并拋出 InterruptedException。除此以外,interrupt() 僅設(shè)置線程的中斷狀態(tài)。在中斷的線程中運(yùn)行的代碼可以稍后輪詢中斷的狀態(tài)以查看是否已經(jīng)請求停止它正在做的事情; 中斷狀態(tài)可以通過 Thread.isInterrupted() 讀取,并且可以在命名不佳的單個(gè)操作Thread.interrupted()中讀取和清除 。

中斷是一種合作機(jī)制。當(dāng)一個(gè)線程中斷另一個(gè)線程時(shí),被中斷的線程不一定會(huì)立即停止它正在做的事情。相反,中斷是一種禮貌地要求另一個(gè)線程在方便的時(shí)候停止它正在做什么的方式。有些方法,比如Thread.sleep()認(rèn)真對待這個(gè)請求,但方法不一定要注意中斷請求。不阻塞但仍可能需要很長時(shí)間才能執(zhí)行完成的方法可以通過輪詢中斷狀態(tài)來尊重中斷請求,并在中斷時(shí)提前返回。你可以自由地忽略中斷請求,但這樣做可能會(huì)影響響應(yīng)速度。

中斷的合作性質(zhì)的一個(gè)好處是它為安全地構(gòu)建可取消的活動(dòng)提供了更大的靈活性。我們很少想立即停止活動(dòng); 如果活動(dòng)在更新期間被取消,程序數(shù)據(jù)結(jié)構(gòu)可能會(huì)處于不一致狀態(tài)。中斷允許可取消活動(dòng)清理正在進(jìn)行的任何工作,恢復(fù)不變量,通知其他活動(dòng)取消事件,然后終止。

處理InterruptedException

如果 throw InterruptedException 意味著這個(gè)方法是一個(gè)阻塞方法,那么調(diào)用一個(gè)阻塞方法意味著你的方法也是一個(gè)阻塞方法,你應(yīng)該有一個(gè)處理策略 InterruptedException。通常最簡單的策略是你自己也拋出 InterruptedException 異常,如清單1 中的 putTask() 和 getTask() 方法所示。這樣做會(huì)使你的方法響應(yīng)中斷,并且通常只需要添加 InterruptedException 到 throws 子句。

清單1.通過不捕獲它來向調(diào)用者傳播InterruptedException

public class TaskQueue {
 private static final int MAX_TASKS = 1000;
 
 private BlockingQueue<Task> queue 
  = new LinkedBlockingQueue<Task>(MAX_TASKS);
 
 public void putTask(Task r) throws InterruptedException { 
  queue.put(r);
 }
 
 public Task getTask() throws InterruptedException { 
  return queue.take();
 }
}

有時(shí)在傳播異常之前需要進(jìn)行一些清理。在這種情況下,你可以捕獲 InterruptedException,執(zhí)行清理,然后重新拋出異常。清單2是一種用于匹配在線游戲服務(wù)中的玩家的機(jī)制,說明了這種技術(shù)。該 matchPlayers() 方法等待兩個(gè)玩家到達(dá)然后開始新游戲。如果在一個(gè)玩家到達(dá)之后但在第二個(gè)玩家到達(dá)之前它被中斷,則在重新投擲之前將該玩家放回隊(duì)列 InterruptedException,以便玩家的游戲請求不會(huì)丟失。

清單2.在重新拋出 InterruptedException 之前執(zhí)行特定于任務(wù)的清理

public class PlayerMatcher {
 private PlayerSource players;
 
 public PlayerMatcher(PlayerSource players) { 
  this.players = players; 
 }
 
 public void matchPlayers() <strong>throws InterruptedException</strong> { 
  Player playerOne, playerTwo;
   try {
    while (true) {
     playerOne = playerTwo = null;
     // 等待兩個(gè)玩家到來以便開始游戲
     playerOne = players.waitForPlayer(); // 會(huì)拋出中斷異常
     playerTwo = players.waitForPlayer(); // 會(huì)拋出中斷異常
     startNewGame(playerOne, playerTwo);
    }
   }
   catch (InterruptedException e) { 
    // 如一個(gè)玩家中斷了, 將這個(gè)玩家放回隊(duì)列
    if (playerOne != null)
     players.addFirst(playerOne);
    // 然后傳播異常
    throw e;
   }
 }
}

不要吞下中斷

有時(shí)拋出 InterruptedException 不是一種選擇,例如當(dāng)通過 Runnable 調(diào)用可中斷方法定義的任務(wù)時(shí)。在這種情況下,你不能重新拋出 InterruptedException,但你也不想做任何事情。當(dāng)阻塞方法檢測到中斷和拋出時(shí) InterruptedException,它會(huì)清除中斷狀態(tài)。如果你抓住 InterruptedException 但不能重新拋出它,你應(yīng)該保留中斷發(fā)生的證據(jù),以便調(diào)用堆棧上的代碼可以了解中斷并在需要時(shí)響應(yīng)它。此任務(wù)通過調(diào)用 interrupt()實(shí)現(xiàn)“重新中斷”當(dāng)前線程,如清單3所示。至少,無論何時(shí)捕獲 InterruptedException 并且不重新拋出它,都要在返回之前重新中斷當(dāng)前線程。

清單3.捕獲InterruptedException后恢復(fù)中斷狀態(tài)

public class TaskRunner implements Runnable {
 private BlockingQueue<Task> queue;
 
 public TaskRunner(BlockingQueue<Task> queue) { 
  this.queue = queue; 
 }
 
 public void run() { 
  try {
    while (true) {
     Task task = queue.take(10, TimeUnit.SECONDS);
     task.execute();
    }
   }
   catch (InterruptedException e) { 
    //重要: 恢復(fù)中斷狀態(tài)
    Thread.currentThread().interrupt();
   }
 }
}

你可以做的最糟糕的事情 InterruptedException 就是吞下它 - 抓住它,既不重新拋出它也不重新確定線程的中斷狀態(tài)。處理你沒有規(guī)劃的異常的標(biāo)準(zhǔn)方法 - 捕獲它并記錄它 - 也算作吞噬中斷,因?yàn)檎{(diào)用堆棧上的代碼將無法找到它。(記錄 InterruptedException 也很愚蠢,因?yàn)楫?dāng)人類讀取日志時(shí),對它做任何事都為時(shí)已晚。)清單4顯示了吞下中斷的常見模式:

清單4.吞下中斷 - 不要這樣做

// 不要這么做!
public class TaskRunner implements Runnable {
  private BlockingQueue<Task> queue;
 
  public TaskRunner(BlockingQueue<Task> queue) { 
    this.queue = queue; 
  }
 
  public void run() { 
    try {
       while (true) {
         Task task = queue.take(10, TimeUnit.SECONDS);
         task.execute();
       }
     }
     catch (InterruptedException swallowed) { 
       /* DON'T DO THIS - RESTORE THE INTERRUPTED STATUS INSTEAD */
       /* 不要這么做 - 要讓線程中斷 */

     }
  }
}

如果你不能重新拋出 InterruptedException,無論你是否計(jì)劃對中斷請求執(zhí)行操作,你仍然希望重新中斷當(dāng)前線程,因?yàn)閱蝹€(gè)中斷請求可能有多個(gè)“收件人”。標(biāo)準(zhǔn)線程池(ThreadPoolExecutor)工作線程實(shí)現(xiàn)響應(yīng)中斷,因此中斷線程池中運(yùn)行的任務(wù)可能具有取消任務(wù)和通知執(zhí)行線程線程池正在關(guān)閉的效果。如果作業(yè)吞下中斷請求,則工作線程可能不會(huì)知道請求了中斷,這可能會(huì)延遲應(yīng)用程序或服務(wù)關(guān)閉。

實(shí)施可取消的任務(wù)

語言規(guī)范中沒有任何內(nèi)容給出任何特定語義的中斷,但在較大的程序中,除了取消之外,很難保持中斷的任何語義。根據(jù)活動(dòng),用戶可以通過 GUI 或通過 JMX 或 Web 服務(wù)等網(wǎng)絡(luò)機(jī)制請求取消。它也可以由程序邏輯請求。例如,如果 Web 爬蟲檢測到磁盤已滿,則可能會(huì)自動(dòng)關(guān)閉自身,或者并行算法可能會(huì)啟動(dòng)多個(gè)線程來搜索解決方案空間的不同區(qū)域,并在其中一個(gè)找到解決方案后取消它們。

僅僅因?yàn)橐粋€(gè)任務(wù)是取消并不意味著它需要一個(gè)中斷請求響應(yīng)立即。對于在循環(huán)中執(zhí)行代碼的任務(wù),通常每次循環(huán)迭代僅檢查一次中斷。根據(jù)循環(huán)執(zhí)行的時(shí)間長短,在任務(wù)代碼通知線程中斷之前可能需要一些時(shí)間(通過使用 Thread.isInterrupted()或通過調(diào)用阻塞方法輪詢中斷狀態(tài))。如果任務(wù)需要更具響應(yīng)性,則可以更頻繁地輪詢中斷狀態(tài)。阻止方法通常在進(jìn)入時(shí)立即輪詢中斷狀態(tài),InterruptedException 如果設(shè)置為提高響應(yīng)性則拋出 。

吞下一個(gè)中斷是可以接受的,當(dāng)你知道線程即將退出時(shí)。這種情況只發(fā)生在調(diào)用可中斷方法的類是一個(gè) Thread,而不是 Runnable 一般或通用庫代碼的一部分時(shí),如清單5所示。它創(chuàng)建一個(gè)枚舉素?cái)?shù)的線程,直到它被中斷并允許線程退出中斷。尋求主要的循環(huán)在兩個(gè)地方檢查中斷:一次是通過輪詢 isInterrupted() while 循環(huán)的頭部中的方法,一次是在調(diào)用阻塞 BlockingQueue.put() 方法時(shí)。

清單5.如果你知道線程即將退出,則可以吞下中斷

public class PrimeProducer extends Thread {
  private final BlockingQueue<BigInteger> queue;
 
  PrimeProducer(BlockingQueue<BigInteger> queue) {
    this.queue = queue;
  }
 
  public void run() {
    try {
      BigInteger p = BigInteger.ONE;
      while (!Thread.currentThread().isInterrupted())
        queue.put(p = p.nextProbablePrime());
    } catch (InterruptedException consumed) {
      /* Allow thread to exit */
      /* 允許線程退出 */
    }
  }
 
  public void cancel() { interrupt(); }
}

不間斷阻塞

并非所有阻止方法都拋出 InterruptedException。輸入和輸出流類可能會(huì)阻止等待 I/O 完成,但它們不會(huì)拋出InterruptedException,并且如果它們被中斷,它們不會(huì)提前返回。但是,在套接字 I/O 的情況下,如果一個(gè)線程關(guān)閉了套接字,那么阻塞其他線程中該套接字上的 I/O 操作將在早期完成SocketException。非阻塞 I/O 類 java.nio 也不支持可中斷 I/O,但可以通過關(guān)閉通道或請求喚醒來類似地取消阻塞操作 Selector。同樣,嘗試獲取內(nèi)在鎖(輸入一個(gè) synchronized 塊)不能被中斷,但 ReentrantLock 支持可中斷的采集模式。

不可取消的任務(wù)

有些任務(wù)只是拒絕被打斷,使它們無法取消。但是,即使是不可取消的任務(wù)也應(yīng)該嘗試保留中斷狀態(tài),以但在調(diào)用堆棧上層的代碼在非可取消任務(wù)完成后想要對發(fā)生的中斷進(jìn)行響應(yīng)。清單6顯示了一個(gè)等待阻塞隊(duì)列直到某個(gè)項(xiàng)可用的方法,無論它是否被中斷。為了成為一個(gè)好公民,它在完成后恢復(fù)最終塊中的中斷狀態(tài),以免剝奪呼叫者的中斷請求。它無法提前恢復(fù)中斷狀態(tài),因?yàn)樗鼤?huì)導(dǎo)致無限循環(huán) - BlockingQueue.take(), 完成后則可以在進(jìn)入時(shí)立即輪詢中斷狀態(tài), 如果發(fā)現(xiàn)中斷狀態(tài)設(shè)置,則可以拋出InterruptedException。

清單6. 在返回之前恢復(fù)中斷狀態(tài)的非可執(zhí)行任務(wù)

public Task getNextTask(BlockingQueue<Task> queue) {
  boolean interrupted = false;
  try {
    while (true) {
      try {
        return queue.take();
      } catch (InterruptedException e) {
        interrupted = true;
        // 失敗了再試
      }
    }
  } finally {
    if (interrupted)
      Thread.currentThread().interrupt();
  }
}

摘要

你可以使用 Java 平臺(tái)提供的協(xié)作中斷機(jī)制來構(gòu)建靈活的取消策略。作業(yè)可以決定它們是否可以取消,它們希望如何響應(yīng)中斷,如果立即返回會(huì)影響應(yīng)用程序的完整性,它們可以推遲中斷以執(zhí)行特定于任務(wù)的清理。即使你想完全忽略代碼中斷,也要確保在捕獲 InterruptedException 并且不重新拋出代碼時(shí)恢復(fù)中斷狀態(tài) ,以便調(diào)用它的代碼能夠發(fā)現(xiàn)中斷。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。

相關(guān)文章

  • 去掉IntelliJ IDEA 中 mybatis 對應(yīng)的 xml 文件警告的教程圖解

    去掉IntelliJ IDEA 中 mybatis 對應(yīng)的 xml 文件警告的教程圖解

    本文通過圖文并茂的形式給大家介紹了去掉IntelliJ IDEA 中 mybatis 對應(yīng)的 xml 文件警告的教程,需要的朋友可以參考下
    2018-06-06
  • JavaWeb使用POI操作Excel文件實(shí)例

    JavaWeb使用POI操作Excel文件實(shí)例

    這篇文章主要介紹了JavaWeb使用POI操作Excel文件,需要的朋友可以參考下
    2017-04-04
  • 全面解析java中的hashtable

    全面解析java中的hashtable

    以下是對java中的hashtable進(jìn)行了詳細(xì)的分析介紹。需要的朋友可以過來參考下
    2013-08-08
  • Java實(shí)現(xiàn)每日給女友微信發(fā)送早安信息

    Java實(shí)現(xiàn)每日給女友微信發(fā)送早安信息

    這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)每日給女友微信發(fā)送早安等微信信息,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以了解一下
    2022-12-12
  • Java中的LinkedHashMap源碼分析

    Java中的LinkedHashMap源碼分析

    這篇文章主要介紹了Java中的LinkedHashMap源碼分析,LinkedHashMap是HashMap的子類,所以基本的操作與hashmap類似,不過呢,在插入、刪除、替換key-value對的時(shí)候,需要的朋友可以參考下
    2023-12-12
  • iReport使用教程(示例教程)

    iReport使用教程(示例教程)

    在使用ireport的過程中,因?yàn)楦鞣N功能都要百度,但是大家使用的例子又千差萬別讓人很苦惱,所以用一個(gè)簡單例子貫穿的展示一下ireport的常見功能
    2021-10-10
  • Java面試必問之ThreadLocal終極篇分享

    Java面試必問之ThreadLocal終極篇分享

    ThreadLocal是什么呢?其實(shí)ThreadLocal并非是一個(gè)線程的本地實(shí)現(xiàn)版本,它并不是一個(gè)Thread,而是thread local variable(線程局部變量),這篇文章主要給大家介紹了關(guān)于Java面試必問之ThreadLocal終極篇的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • Java快速批量移動(dòng)文件的實(shí)現(xiàn)方法

    Java快速批量移動(dòng)文件的實(shí)現(xiàn)方法

    這篇文章主要介紹了Java快速批量移動(dòng)文件的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2014-03-03
  • SpringBoot集成RabbitMQ的方法(死信隊(duì)列)

    SpringBoot集成RabbitMQ的方法(死信隊(duì)列)

    這篇文章主要介紹了SpringBoot集成RabbitMQ的方法(死信隊(duì)列),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • ElasticSearch的完整安裝教程

    ElasticSearch的完整安裝教程

    這篇文章主要給大家分享介紹了ElasticSearch的完整安裝教程,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用ElasticSearch具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評論