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

深入分析JAVA 多線程--interrupt()和線程終止方式

 更新時(shí)間:2020年06月23日 09:21:48   作者:凌傾-學(xué)無止境  
這篇文章主要介紹了JAVA 多線程--interrupt()和線程終止方式的的相關(guān)資料,文中代碼非常細(xì)致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

一、interrupt() 介紹

interrupt() 定義在 Thread 類中,作用是中斷本線程。

本線程中斷自己是被允許的;其它線程調(diào)用本線程的 interrupt() 方法時(shí),會通過 checkAccess() 檢查權(quán)限。這有可能拋出 SecurityException 異常。
如果本線程是處于阻塞狀態(tài):調(diào)用線程的 wait() , wait(long) 或 wait(long, int) 會讓它進(jìn)入等待(阻塞)狀態(tài),或者調(diào)用線程的 join(),join(long),join(long, int),sleep(long),sleep(long, int) 也會讓它進(jìn)入阻塞狀態(tài)。若線程在阻塞狀態(tài)時(shí),調(diào)用了它的 interrupt() 方法,那么它的“中斷狀態(tài)”會被清除并且會收到一個 InterruptedException 異常。例如,線程通過 wait() 進(jìn)入阻塞狀態(tài),此時(shí)通過 interrupt() 中斷該線程;調(diào)用 interrupt() 會立即將線程的中斷標(biāo)記設(shè)為 true,但是由于線程處于阻塞狀態(tài),所以該“中斷標(biāo)記”會立即被清除為 “false”,同時(shí),會產(chǎn)生一個 InterruptedException 的異常。
如果線程被阻塞在一個 Selector 選擇器中,那么通過 interrupt() 中斷它時(shí);線程的中斷標(biāo)記會被設(shè)置為 true,并且它會立即從選擇操作中返回。
如果不屬于前面所說的情況,那么通過 interrupt() 中斷線程時(shí),它的中斷標(biāo)記會被設(shè)置為 true。
中斷一個“已終止的線程”不會產(chǎn)生任何操作。

二、線程終止方式

Thread中的 stop() 和 suspend() 方法,由于固有的不安全性,已經(jīng)建議不再使用!
下面,我先分別討論線程在“阻塞狀態(tài)”和“運(yùn)行狀態(tài)”的終止方式,然后再總結(jié)出一個通用的方式。

(一)、終止處于“阻塞狀態(tài)”的線程.

通常,我們通過“中斷”方式終止處于“阻塞狀態(tài)”的線程。
當(dāng)線程由于被調(diào)用了 sleep(),,wait(),join() 等方法而進(jìn)入阻塞狀態(tài);若此時(shí)調(diào)用線程的 interrupt() 將線程的中斷標(biāo)記設(shè)為 true。由于處于阻塞狀態(tài),中斷標(biāo)記會被清除,同時(shí)產(chǎn)生一個InterruptedException 異常。將 InterruptedException 放在適當(dāng)?shù)奈恢镁湍芙K止線程,形式如下:

public void run() {
  try {
    while (true) {
      // 執(zhí)行業(yè)務(wù)
    }
  } catch (InterruptedException ie) { 
    // 由于產(chǎn)生InterruptedException異常,退出while(true)循環(huán),線程終止!
  }
}

說明:

在while(true)中不斷的執(zhí)行業(yè)務(wù)代碼,當(dāng)線程處于阻塞狀態(tài)時(shí),調(diào)用線程的 interrupt() 產(chǎn)生 InterruptedException 中斷。中斷的捕獲在 while(true) 之外,這樣就退出了 while(true) 循環(huán)!

注意:

對 InterruptedException 的捕獲務(wù)一般放在 while(true) 循環(huán)體的外面,這樣,在產(chǎn)生異常時(shí)就退出了 while(true) 循環(huán)。否則,InterruptedException 在 while(true) 循環(huán)體之內(nèi),就需要額外的添加退出處理。形式如下:

public void run() {
  while (true) {
    try {
      // 執(zhí)行任務(wù)...
    } catch (InterruptedException ie) { 
      // InterruptedException在while(true)循環(huán)體內(nèi)。
      // 當(dāng)線程產(chǎn)生了InterruptedException異常時(shí),while(true)仍能繼續(xù)運(yùn)行!需要手動退出
      break;
    }
  }
}

說明:

上面的 InterruptedException 異常的捕獲在 whle(true) 之內(nèi)。當(dāng)產(chǎn)生 InterruptedException 異常時(shí),被 catch 處理之外,仍然在 while(true) 循環(huán)體內(nèi);要退出 while(true) 循環(huán)體,需要額外的執(zhí)行退出while(true) 的操作。

(二)、終止處于“運(yùn)行狀態(tài)”的線程

通常,我們通過“標(biāo)記”方式終止處于“運(yùn)行狀態(tài)”的線程。其中,包括“中斷標(biāo)記”和“額外添加標(biāo)記”。

1、通過“中斷標(biāo)記”終止線程

public void run() {
  while (!isInterrupted()) {
    // 執(zhí)行任務(wù)...
  }
}

說明:

isInterrupted() 是判斷線程的中斷標(biāo)記是不是為 true。當(dāng)線程處于運(yùn)行狀態(tài),并且我們需要終止它時(shí);可以調(diào)用線程的 interrupt() 方法,使用線程的中斷標(biāo)記為 true,即 isInterrupted() 會返回true。此時(shí),就會退出while循環(huán)。

注意:interrupt() 并不會終止處于“運(yùn)行狀態(tài)”的線程!它會將線程的中斷標(biāo)記設(shè)為 true。

2、通過“額外添加標(biāo)記”終止線程

private volatile boolean flag= true;
protected void stopTask() {
  flag = false;
}
public void run() {
  while (flag) {
    // 執(zhí)行任務(wù)...
  }
}

說明:

線程中有一個 flag 標(biāo)記,它的默認(rèn)值是 true;并且我們提供 stopTask() 來設(shè)置 flag 標(biāo)記。當(dāng)我們需要終止該線程時(shí),調(diào)用該線程的 stopTask() 方法就可以讓線程退出 while 循環(huán)。

注意:將 flag 定義為 volatile 類型,是為了保證 flag 的可見性。即其它線程通過 stopTask() 修改了 flag 之后,本線程能看到修改后的 flag 的值。

(三)、通過方式

綜合線程處于“阻塞狀態(tài)”和“運(yùn)行狀態(tài)”的終止方式,比較通用的終止線程的形式如下:

public void run() {
  try {
    // 1. isInterrupted()保證,只要中斷標(biāo)記為true就終止線程。
    while (!isInterrupted()) {
      // 執(zhí)行任務(wù)...
    }
  } catch (InterruptedException ie) { 
    // 2. InterruptedException異常保證,當(dāng)InterruptedException異常產(chǎn)生時(shí),線程被終止。
  }
}

1、isInterrupted()保證,只要中斷標(biāo)記為 true 就終止線程。
2、InterruptedException 異常保證,當(dāng) InterruptedException 異常產(chǎn)生時(shí),線程被終止。

三、示例

public class InterruptTest {
  public static void main(String[] args) {
    try {
      Thread t1 = new MyThread("t1"); // 新建線程t1
      System.out.println(t1.getName() + "[" + t1.getState() + "] is new.");
      
      t1.start();// 啟動線程t1
      System.out.println(t1.getName() + "[" + t1.getState() + "] is started.");
      
      Thread.sleep(300);// 休眠300毫秒,然后主線程給t1發(fā)“中斷”指令,查看t1狀態(tài)
      t1.interrupt();
      System.out.println(t1.getName() + "[" + t1.getState() + "] is interrupted.");
      
      Thread.sleep(300);// 休眠300毫秒,然后查看t1狀態(tài)
      System.out.println(t1.getName() + "[" + t1.getState() + "] is interrupted now.");
    }catch(InterruptedException e) {
      e.printStackTrace();
    }
  }
}
class MyThread extends Thread{
  public MyThread(String name) {
    super(name);
  }
  @Override
  public void run() {
    try {
      int i = 0;
      while(!isInterrupted()) {
        Thread.sleep(100);// 休眠100毫秒
        ++i;
        System.out.println(Thread.currentThread().getName() + "[" + this.getState() + "] loop " + i);
      }
    }catch(InterruptedException e) {
      System.out.println(Thread.currentThread().getName() + "[" + this.getState() + "] catch InterruptedException");
    }
  }
}

運(yùn)行結(jié)果

t1 [ NEW ] is new.
t1 [ RUNNABLE ] is started.
t1 [ RUNNABLE ] loop 1
t1 [ RUNNABLE ] loop 2
t1 [ RUNNABLE ] loop 3
t1 [ RUNNABLE ] catch InterruptedException
t1 [ TERMINATED ] is interrupted.
t1 [ TERMINATED ] is interrupted now.

說明:

①、主線程 main 中通過 new MyThread("t1") 創(chuàng)建線程 t1,之后通過 t1.start() 啟動線程 t1。

②、t1 啟動之后,會不斷的檢查它的中斷標(biāo)記,如果中斷標(biāo)記為“false”;則休眠 100ms。

③、t1 休眠之后,會切換到主線程main;主線程再次運(yùn)行時(shí),會執(zhí)行t1.interrupt()中斷線程t1。t1收到中斷指令之后,會將t1的中斷標(biāo)記設(shè)置“false”,而且會拋出 InterruptedException 異常。在 t1 的 run() 方法中,是在循環(huán)體 while 之外捕獲的異常;因此循環(huán)被終止。

我們對上面的結(jié)果進(jìn)行小小的修改,將run()方法中捕獲InterruptedException異常的代碼塊移到while循環(huán)體內(nèi)。

public class InterruptTest {
  public static void main(String[] args) {
    try {
      Thread t1 = new MyThread("t1"); // 新建線程t1
      System.out.println(t1.getName() + " [ " + t1.getState() + " ] is new.");
      
      t1.start();// 啟動線程t1
      System.out.println(t1.getName() + " [ " + t1.getState() + " ] is started.");
      
      Thread.sleep(300);// 休眠300毫秒,然后主線程給t1發(fā)“中斷”指令,查看t1狀態(tài)
      t1.interrupt();
      System.out.println(t1.getName() + " [ " + t1.getState() + " ] is interrupted.");
      
      Thread.sleep(300);// 休眠300毫秒,然后查看t1狀態(tài)
      System.out.println(t1.getName() + " [ " + t1.getState() + " ] is interrupted now.");
    }catch(InterruptedException e) {
      e.printStackTrace();
    }
    
  }
}
class MyThread extends Thread{
  public MyThread(String name) {
    super(name);
  }
  @Override
  public void run() {
    int i = 0;
    while(!isInterrupted()) {
      try {
        Thread.sleep(100); // 休眠100ms
      } catch (InterruptedException ie) { 
        System.out.println(Thread.currentThread().getName() +" [ "+this.getState()+" ] catch InterruptedException."); 
      }
      i++;
      System.out.println(Thread.currentThread().getName()+" [ "+this.getState()+" ] loop " + i); 
    }
  }
}

運(yùn)行結(jié)果

t1 [ NEW ] is new.
t1 [ RUNNABLE ] is started.
t1 [ RUNNABLE ] loop 1
t1 [ RUNNABLE ] loop 2
t1 [ TIMED_WAITING ] is interrupted.
t1 [ RUNNABLE ] catch InterruptedException.
t1 [ RUNNABLE ] loop 3
t1 [ RUNNABLE ] loop 4
t1 [ RUNNABLE ] loop 5
t1 [ RUNNABLE ] loop 6
t1 [ RUNNABLE ] is interrupted now.
t1 [ RUNNABLE ] loop 7
...... // 無限循環(huán)

說明:

程序進(jìn)入了死循環(huán)了。

這是因?yàn)椋瑃1在“等待(阻塞)狀態(tài)”時(shí),被 interrupt() 中斷;此時(shí),會清除中斷標(biāo)記(即 isInterrupted() 會返回 false),而且會拋出 InterruptedException 異常(該異常在while循環(huán)體內(nèi)被捕獲)。因此,t1理所當(dāng)然的會進(jìn)入死循環(huán)了。

解決該問題,需要我們在捕獲異常時(shí),額外的進(jìn)行退出 while 循環(huán)的處理。例如,在 MyThread 的 catch(InterruptedException) 中添加 break 或 return 就能解決該問題。

下面是通過“額外添加標(biāo)記”的方式終止“狀態(tài)狀態(tài)”的線程的示例:

public class InterruptTest {
  public static void main(String[] args) {
    try {
      MyThread t1 = new MyThread("t1"); // 新建線程t1
      System.out.println(t1.getName() + " [ " + t1.getState() + " ] is new.");
      
      t1.start();// 啟動線程t1
      System.out.println(t1.getName() + " [ " + t1.getState() + " ] is started.");
      
      Thread.sleep(300);// 休眠300毫秒,然后主線程給t1發(fā)“中斷”指令,查看t1狀態(tài)
      t1.stopTask();
      System.out.println(t1.getName() + " [ " + t1.getState() + " ] is interrupted.");
      
      Thread.sleep(300);// 休眠300毫秒,然后查看t1狀態(tài)
      System.out.println(t1.getName() + " [ " + t1.getState() + " ] is interrupted now.");
    }catch(InterruptedException e) {
      e.printStackTrace();
    }
    
  }
}
class MyThread extends Thread{
  private volatile boolean flag = true;
  public void stopTask() {
    flag = false;
  }
  public MyThread(String name) {
    super(name);
  }
  @Override
  public void run() {
    synchronized (this) {
      int i = 0;
      while(flag) {
        try {
          Thread.sleep(100); // 休眠100ms
        } catch (InterruptedException ie) { 
          System.out.println(Thread.currentThread().getName() +" [ "+this.getState()+" ] catch InterruptedException."); 
          break;
        }
        i++;
        System.out.println(Thread.currentThread().getName()+" [ "+this.getState()+" ] loop " + i); 
      }
    }
    
  }
}

運(yùn)行結(jié)果

t1 [ NEW ] is new.
t1 [ RUNNABLE ] is started.
t1 [ RUNNABLE ] loop 1
t1 [ RUNNABLE ] loop 2
t1 [ RUNNABLE ] loop 3
t1 [ RUNNABLE ] is interrupted.
t1 [ TERMINATED ] is interrupted now.

四、interrupted() 和 isInterrupted()的區(qū)別

interrupted() 和 isInterrupted()都能夠用于檢測對象的“中斷標(biāo)記”。
區(qū)別是,interrupted() 除了返回中斷標(biāo)記之外,它還會清除中斷標(biāo)記(即將中斷標(biāo)記設(shè)為 false);而 isInterrupted() 僅僅返回中斷標(biāo)記。

以上就是深入分析JAVA 多線程--interrupt()和線程終止方式的詳細(xì)內(nèi)容,更多關(guān)于JAVA 多線程--interrupt()和線程終止的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 關(guān)于快速測試API接口的一個新技能

    關(guān)于快速測試API接口的一個新技能

    這篇文章主要給大家介紹了關(guān)于快速測試API接口的一個新技能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-06-06
  • Spring緩存注解@Cacheable @CacheEvit @CachePut使用介紹

    Spring緩存注解@Cacheable @CacheEvit @CachePut使用介紹

    Spring在3.1版本,就提供了一條基于注解的緩存策略,實(shí)際使用起來還是很絲滑的,本文將針對幾個常用的注解進(jìn)行簡單的介紹說明,有需要的小伙伴可以嘗試一下
    2021-07-07
  • MyBatis插入時(shí)獲取自增主鍵方法

    MyBatis插入時(shí)獲取自增主鍵方法

    MyBatis 3.2.6插入時(shí)候獲取自增主鍵方法有兩種,下面以以MySQL5.5為例通過兩種方法給大家介紹mybatis獲取自增主鍵的方法,一起看看吧
    2016-11-11
  • Java 開啟多線程常見的4種方法

    Java 開啟多線程常見的4種方法

    本文主要介紹了Java 開啟多線程常見的4種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • jsoup如何爬取圖片到本地

    jsoup如何爬取圖片到本地

    這篇文章主要為大家詳細(xì)介紹了jsoup如何爬取圖片到本地,jsoup爬取網(wǎng)站信息,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java框架Quartz中的Trigger簡析

    Java框架Quartz中的Trigger簡析

    這篇文章主要介紹了Java框架Quartz中的Trigger簡析,所有類型的trigger都有TriggerKey這個屬性,表示trigger的身份;除此之外,trigger還有很多其它的公共屬性,這些屬性,在構(gòu)建trigger的時(shí)候可以通過TriggerBuilder設(shè)置,需要的朋友可以參考下
    2023-11-11
  • SpringBoot使用AOP實(shí)現(xiàn)統(tǒng)計(jì)全局接口訪問次數(shù)詳解

    SpringBoot使用AOP實(shí)現(xiàn)統(tǒng)計(jì)全局接口訪問次數(shù)詳解

    這篇文章主要介紹了SpringBoot通過AOP實(shí)現(xiàn)對全局接口訪問次數(shù)的統(tǒng)計(jì),文章從相關(guān)問題展開全文內(nèi)容詳情,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-06-06
  • idea git未提交代碼文件名字變色(圖解)

    idea git未提交代碼文件名字變色(圖解)

    這篇文章主要介紹了idea git未提交代碼文件名字變色,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • springboot配置https訪問的方法

    springboot配置https訪問的方法

    這篇文章主要介紹了springboot配置https訪問的方法,需要的朋友可以參考下
    2018-11-11
  • 解決SpringBoot webSocket 資源無法加載、tomcat啟動報(bào)錯的問題

    解決SpringBoot webSocket 資源無法加載、tomcat啟動報(bào)錯的問題

    這篇文章主要介紹了解決SpringBoot webSocket 資源無法加載、tomcat啟動報(bào)錯的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11

最新評論