奶头挺立呻吟高潮av全片,成人试看120秒体验区,性欧美极品v,A片高潮抽搐揉捏奶头视频

java語言

淺談Java線程中斷的本質深入理解

時間:2024-08-23 15:07:03 java語言 我要投稿
  • 相關推薦

淺談Java線程中斷的本質深入理解

  一、Java中斷的現象

  首先,看看Thread類里的幾個方法:

  public static booleaninterrupted測試當前線程是否已經中斷。線程的中斷狀態由該方法清除。換句話說,如果連續兩次調用該方法,則第二次調用將返回 false(在第一次調用已清除了其中斷狀態之后,且第二次調用檢驗完中斷狀態前,當前線程再次中斷的情況除外)。public booleanisInterrupted()測試線程是否已經中斷。線程的中斷狀態不受該方法的影響。public voidinterrupt()中斷線程。

  上面列出了與中斷有關的幾個方法及其行為,可以看到interrupt是中斷線程。如果不了解Java的中斷機制,這樣的一種解釋極容易造成誤解,認為調用了線程的interrupt方法就一定會中斷線程。

  其實,Java的中斷是一種協作機制。也就是說調用線程對象的interrupt方法并不一定就中斷了正在運行的線程,它只是要求線程自己在合適的時機中斷自己。每個線程都有一個boolean的中斷狀態(不一定就是對象的屬性,事實上,該狀態也確實不是Thread的字段),interrupt方法僅僅只是將該狀態置為true

  復制代碼 代碼如下:

  public class TestInterrupt {

  public static void main(String[] args) {

  Thread t = new MyThread();

  t.start();

  t.interrupt();

  System.out.println("已調用線程的interrupt方法");

  }

  static class MyThread extends Thread {

  public void run() {

  int num = longTimeRunningNonInterruptMethod(2, 0);

  System.out.println("長時間任務運行結束,num=" + num);

  System.out.println("線程的中斷狀態:" + Thread.interrupted());

  }

  private static int longTimeRunningNonInterruptMethod(int count, int initNum) {

  for(int i=0; i<count; i++) {

  for(int j=0; j<Integer.MAX_VALUE; j++) {

  initNum ++;

  }

  }

  return initNum;

  }

  }

  }

  一般情況下,會打印如下內容:

  已調用線程的interrupt方法

  長時間任務運行結束,num=-2

  線程的中斷狀態:true

  可見,interrupt方法并不一定能中斷線程。但是,如果改成下面的程序,情況會怎樣呢?

  復制代碼 代碼如下:

  import java.util.concurrent.TimeUnit;

  public class TestInterrupt {

  public static void main(String[] args) {

  Thread t = new MyThread();

  t.start();

  t.interrupt();

  System.out.println("已調用線程的interrupt方法");

  }

  static class MyThread extends Thread {

  public void run() {

  int num = -1;

  try {

  num = longTimeRunningInterruptMethod(2, 0);

  } catch (InterruptedException e) {

  System.out.println("線程被中斷");

  throw new RuntimeException(e);

  }

  System.out.println("長時間任務運行結束,num=" + num);

  System.out.println("線程的中斷狀態:" + Thread.interrupted());

  }

  private static int longTimeRunningInterruptMethod(int count, int initNum) throws InterruptedException{

  for(int i=0; i<count; i++) {

  TimeUnit.SECONDS.sleep(5);

  }

  return initNum;

  }

  }

  }

  經運行可以發現,程序拋出異常停止了,run方法里的后兩條打印語句沒有執行。那么,區別在哪里?

  一般說來,如果一個方法聲明拋出InterruptedException,表示該方法是可中斷的(沒有在方法中處理中斷卻也聲明拋出InterruptedException的除外),也就是說可中斷方法會對interrupt調用做出響應(例如sleep響應interrupt的操作包括清除中斷狀態,拋出InterruptedException),如果interrupt調用是在可中斷方法之前調用,可中斷方法一定會處理中斷,像上面的例子,interrupt方法極可能在run未進入sleep的時候就調用了,但sleep檢測到中斷,就會處理該中斷。如果在可中斷方法正在執行中的時候調用interrupt,會怎么樣呢?這就要看可中斷方法處理中斷的時機了,只要可中斷方法能檢測到中斷狀態為true,就應該處理中斷。讓我們為開頭的那段代碼加上中斷處理。

  那么自定義的可中斷方法該如何處理中斷呢?那就是在適合處理中斷的地方檢測線程中斷狀態并處理。

  復制代碼 代碼如下:

  public class TestInterrupt {

  public static void main(String[] args) throws Exception {

  Thread t = new MyThread();

  t.start();

  // TimeUnit.SECONDS.sleep(1);//如果不能看到處理過程中被中斷的情形,可以啟用這句再看看效果

  t.interrupt();

  System.out.println("已調用線程的interrupt方法");

  }

  static class MyThread extends Thread {

  public void run() {

  int num;

  try {

  num = longTimeRunningNonInterruptMethod(2, 0);

  } catch (InterruptedException e) {

  throw new RuntimeException(e);

  }

  System.out.println("長時間任務運行結束,num=" + num);

  System.out.println("線程的中斷狀態:" + Thread.interrupted());

  }

  private static int longTimeRunningNonInterruptMethod(int count, int initNum) throws InterruptedException {

  if(interrupted()) {

  throw new InterruptedException("正式處理前線程已經被請求中斷");

  }

  for(int i=0; i<count; i++) {

  for(int j=0; j<Integer.MAX_VALUE; j++) {

  initNum ++;

  }

  //假如這就是一個合適的地方

  if(interrupted()) {

  //回滾數據,清理操作等

  throw new InterruptedException("線程正在處理過程中被中斷");

  }

  }

  return initNum;

  }

  }

  }

  如上面的代碼,方法longTimeRunningMethod此時已是一個可中斷的方法了。在進入方法的時候判斷是否被請求中斷,如果是,就不進行相應的處理了;處理過程中,可能也有合適的地方處理中斷,例如上面最內層循環結束后。

  這段代碼中檢測中斷用了Thread的靜態方法interrupted,它將中斷狀態置為false,并將之前的狀態返回,而isInterrupted只是檢測中斷,并不改變中斷狀態。一般來說,處理過了中斷請求,應該將其狀態置為false。但具體還要看實際情形。

  二、Java中斷的本質

  在歷史上,Java試圖提供過搶占式限制中斷,但問題多多,例如已被廢棄的Thread.stop、Thread.suspend和 Thread.resume等。另一方面,出于Java應用代碼的健壯性的考慮,降低了編程門檻,減少不清楚底層機制的程序員無意破壞系統的概率。

  如今,Java的線程調度不提供搶占式中斷,而采用協作式的中斷。其實,協作式的中斷,原理很簡單,就是輪詢某個表示中斷的標記,我們在任何普通代碼的中都可以實現。 例如下面的代碼:

  復制代碼 代碼如下:

  volatile bool isInterrupted;

  //…

  while(!isInterrupted) {

  compute();

  }

  但是,上述的代碼問題也很明顯。當compute執行時間比較長時,中斷無法及時被響應。另一方面,利用輪詢檢查標志變量的方式,想要中斷wait和sleep等線程阻塞操作也束手無策。

  如果仍然利用上面的思路,要想讓中斷及時被響應,必須在虛擬機底層進行線程調度的對標記變量進行檢查。是的,JVM中確實是這樣做的。下面摘自java.lang.Thread的源代碼:

  復制代碼 代碼如下:

  public static boolean interrupted() {

  return currentThread().isInterrupted(true);

  }

  //…

  private native boolean isInterrupted(boolean ClearInterrupted);

  可以發現,isInterrupted被聲明為native方法,取決于JVM底層的實現。

  實際上,JVM內部確實為每個線程維護了一個中斷標記。但應用程序不能直接訪問這個中斷變量,必須通過下面幾個方法進行操作:

  復制代碼 代碼如下:

  public class Thread {

  //設置中斷標記

  public void interrupt() { ... }

  //獲取中斷標記的值

  public boolean isInterrupted() { ... }

  //清除中斷標記,并返回上一次中斷標記的值

  public static boolean interrupted() { ... }

  ...

  }

  通常情況下,調用線程的interrupt方法,并不能立即引發中斷,只是設置了JVM內部的中斷標記。因此,通過檢查中斷標記,應用程序可以做一些特殊操作,也可以完全忽略中斷。

  你可能想,如果JVM只提供了這種簡陋的中斷機制,那和應用程序自己定義中斷變量并輪詢的方法相比,基本也沒有什么優勢。

  JVM內部中斷變量的主要優勢,就是對于某些情況,提供了模擬自動“中斷陷入”的機制。

  在執行涉及線程調度的阻塞調用時(例如wait、sleep和join),如果發生中斷,被阻塞線程會“盡可能快的”拋出InterruptedException。因此,我們就可以用下面的代碼框架來處理線程阻塞中斷:

  復制代碼 代碼如下:

  try {

  //wait、sleep或join

  }

  catch(InterruptedException e) {

  //某些中斷處理工作

  }

  所謂“盡可能快”,我猜測JVM就是在線程調度調度的間隙檢查中斷變量,速度取決于JVM的實現和硬件的性能。

  三、一些不會拋出 InterruptedException 的線程阻塞操作

  然而,對于某些線程阻塞操作,JVM并不會自動拋出InterruptedException異常。例如,某些I/O操作和內部鎖操作。對于這類操作,可以用其他方式模擬中斷:

  1)java.io中的異步socket I/O

  讀寫socket的時候,InputStream和OutputStream的read和write方法會阻塞等待,但不會響應java中斷。不過,調用Socket的close方法后,被阻塞線程會拋出SocketException異常。

  2)利用Selector實現的異步I/O

  如果線程被阻塞于Selector.select(在java.nio.channels中),調用wakeup方法會引起ClosedSelectorException異常。

  3)鎖獲取

  如果線程在等待獲取一個內部鎖,我們將無法中斷它。但是,利用Lock類的lockInterruptibly方法,我們可以在等待鎖的同時,提供中斷能力。

  四、兩條編程原則

  另外,在任務與線程分離的框架中,任務通常并不知道自身會被哪個線程調用,也就不知道調用線程處理中斷的策略。所以,在任務設置了線程中斷標記后,并不能確保任務會被取消。因此,有以下兩條編程原則:

  1)除非你知道線程的中斷策略,否則不應該中斷它。

  這條原則告訴我們,不應該直接調用Executer之類框架中線程的interrupt方法,應該利用諸如Future.cancel的方法來取消任務。

  2)任務代碼不該猜測中斷對執行線程的含義。

  這條原則告訴我們,一般代碼遇在到InterruptedException異常時,不應該將其捕獲后“吞掉”,而應該繼續向上層代碼拋出。

  總之,Java中的非搶占式中斷機制,要求我們必須改變傳統的搶占式中斷思路,在理解其本質的基礎上,采用相應的原則和模式來編程。

【淺談Java線程中斷的本質深入理解】相關文章:

深入理解java的反射04-02

java的多線程12-04

java多線程03-27

最新的Java容器類的深入理解04-02

java語言的多線程11-25

java線程的幾種狀態12-14

淺談理解Java中的弱引用04-02

Java線程編程中的主線程詳細介紹04-02

Java Tomcat和激活MyEclips的深入理解04-02

主站蜘蛛池模板: 古蔺县| 周至县| 灵宝市| 潼南县| 沁源县| 军事| 东莞市| 仁布县| 无极县| 肇州县| 衡南县| 巫溪县| 平阳县| 武夷山市| 卫辉市| 荔浦县| 郑州市| 昌乐县| 东城区| 东光县| 乌鲁木齐县| 海南省| 潞西市| 甘泉县| 越西县| 鄂州市| 缙云县| 襄汾县| 绥阳县| 鄂尔多斯市| 辰溪县| 华亭县| 石阡县| 隆化县| 聂荣县| 湘乡市| 勃利县| 普安县| 多伦县| 资中县| 武义县|