最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Java 線程中斷

 更新時間:2021年02月19日 11:21:50   作者:小小青葉  
這篇文章主要介紹了Java 線程中斷的相關(guān)資料,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下

一、前言

大家肯定都使用過 Java 線程開發(fā)(Thread / Runnable),啟動一個線程的做法通常是:

new Thread(new Runnable(
 @Override
 public void run() {
  // todo sth...
 }
)).start();

然而線程退出,大家是如何做的呢?一般做法可能不外乎以下兩種:

  • 設(shè)置一個標(biāo)志位:true / false 來退出;
  • 強(qiáng)制退出:thread.stop;(我相信,現(xiàn)在應(yīng)該沒人會使用這種方式了,因?yàn)镴DK也很早就廢棄了該方法)

可能還會有人提出,我可以用中斷來退出線程! 我只能說:Too Young Too Simple!中斷并不會使得線程結(jié)束而退出,中斷(interrupt)只是喚醒被阻塞的線程而已。

本篇,我們就來好好的聊聊:線程中斷,以及如何正確的使用線程中斷,和正確的線程退出。

二、為何 Thread.stop 被廢棄

This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it 
has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the 
objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to 
other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply 
modifies some variable to indicate that the target thread should stop running. The target thread should check this 
variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop 
running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method 
should be used to interrupt the wait.

以上是官方 JDK 中的源碼注釋說明,其含義如下:

**Thread.stop 方法天生就不安全。**使用該方法來停止線程,將會導(dǎo)致其它因?yàn)楸O(jiān)視器鎖『監(jiān)視器我們在 synchronized 中就講過,是 Java 的內(nèi)置鎖』而被鎖住的線程全部都解鎖?。ū举|(zhì)的后果是:沒有檢查的 ThreadDeath 異常會在棧中傳播,因而使得監(jiān)視器鎖解鎖)。如果任何一個被監(jiān)視器鎖給鎖住的對象處于一個不一致的狀態(tài),那么其被解鎖后將會被其它線程可見,潛在的結(jié)果是產(chǎn)生任何后果。**我們應(yīng)該使用一個變量來代替使用 stop 方法,告訴目標(biāo)線程退出『這里就是我們開頭所說的第一種方法,設(shè)置一個標(biāo)志位』。**目標(biāo)線程應(yīng)該周期性的檢查這個變量,并根據(jù)這個變量來正確的退出 run 方法。如果目標(biāo)線程處于阻塞/休眠狀態(tài)(如:使用 wait、sleep、yield 方法后,線程讓出了 CPU 使用權(quán),進(jìn)而阻塞/休眠),此時,該標(biāo)志位變量將不會起作用,那么,應(yīng)該使用 interrupt 方法來中斷目標(biāo)線程的阻塞/休眠狀態(tài),將其喚醒!

對于 ThreadDeath 對象,官方還有補(bǔ)充:

  • 線程可以在幾乎任何地方拋出 ThreadDeath 異常。由于這一點(diǎn),所有的同步方法和(代碼)塊將必須被考慮得事無巨細(xì)。
  • 線程在清理第一個 ThreadDeath 異常的時候(在 catch 或 finally 語句中),可能會拋出第二個。清理工作將不得不重復(fù)直到到其成功。保障這一點(diǎn)的代碼將會很復(fù)雜。

所以,我們也別想著去 try-catch ThreadDeath Exception!

同樣,被廢棄的還有 Thread.resume 和 Thread.suspend。這倆方法有造成死鎖的危險:

  • 使用suspend時,并不會釋放鎖;
  • 如果存在某種情況要先獲取該鎖,再進(jìn)行resume,那么就造成死鎖了;

取代這兩方法的正確方式是:Object.wait 和 Object.notify :

因?yàn)?Object.wait 進(jìn)入阻塞時,會釋放鎖。

三、線程中斷的含義

Thread 中有三個與中斷相關(guān)的方法:

  • 成員方法 interrupt():設(shè)置線程中斷標(biāo)志為 true ;
  • 成員方法 isInterrupted():獲取線程的中斷狀態(tài),默認(rèn)為 false,調(diào)用 interrupt() 后,該方法返回 true;
  • 靜態(tài)方法 Thread.interrupted():獲取線程的中斷狀態(tài),并且清除中斷狀態(tài)(設(shè)置為 false);

注:如果線程中斷后,連續(xù)兩次調(diào)用 Thread.interrupted(),第一次是 true & 清除狀態(tài),第二次結(jié)果是 false。

3.1、初步了解

我們先來通過一個例子來初步了解 thread.interrupt :

public class InterruptDemo implements Runnable {
 @Override
 public void run() {
  while (true) {
   System.out.println("Thread running...");
  }
 }

 public static void main(String[] args) throws InterruptedException {
  Thread thread = new Thread(new InterruptDemo(), "InterruptDemo");

  System.out.println("start thread");
  thread.start();

  Thread.sleep(50);
  System.out.println("interrupt thread");
  thread.interrupt();

  Thread.sleep(50);
  System.out.println("thread's status = " + thread.isInterrupted());
 }
}

輸出結(jié)果:

start thread
Thread running...
Thread running...
......
interrupt thread
Thread running...
Thread running...
......
thread's status = true
Thread running...
......

我們可以看到,即便我們調(diào)用了 thread.interrupt 方法,線程也并沒有退出,仍舊繼續(xù)運(yùn)行。因此,這個例子證明了一點(diǎn):我們并不能通過"我們所認(rèn)為的"中斷來試圖"結(jié)束"正在運(yùn)行的線程。

3.2、中斷即喚醒阻塞/休眠的線程

同樣,我們再來看一個例子:

public class InterruptDemo implements Runnable {
 @Override
 public void run() {
  while (true) {
   System.out.println("Thread will sleep 10s ------------------------- running");
   long timestamp = System.currentTimeMillis();
   try {
    Thread.sleep(10000);
   } catch (InterruptedException e) {
    System.out.println("thread interrupted...");
   }

   timestamp = System.currentTimeMillis() - timestamp;
   System.out.println("Thread run, total sleep = " + timestamp + "(ms)");
  }
 }

 public static void main(String[] args) throws InterruptedException {
  Thread thread = new Thread(new InterruptDemo(), "InterruptDemo");

  System.out.println("start thread");
  thread.start();
  Thread.sleep(3000);
  System.out.println("interrupt thread");
  thread.interrupt();
  System.out.println("main exit");
 }
}

輸出結(jié)果:

start thread
Thread will sleep 10s ------------------------- running
interrupt thread
main exit
thread interrupted...
Thread run, total sleep = 3002(ms)
Thread will sleep 10s ------------------------- running
Thread run, total sleep = 10002(ms)
Thread will sleep 10s ------------------------- running

我們可以看到,線程啟動后,進(jìn)入睡眠(10s),3秒后被中斷喚醒,執(zhí)行完一個 while 后再次進(jìn)入第二次睡眠(10s),然后周而復(fù)始。

3.3、一般標(biāo)志位法退出線程

public class InterruptDemo implements Runnable {
 private static final AtomicBoolean running = new AtomicBoolean(true);

 @Override
 public void run() {
  while (running.get()) {
   long timestamp = System.currentTimeMillis();
   timestamp = System.currentTimeMillis() - timestamp;
   System.out.println("Thread run, total sleep = " + timestamp + "(ms)");
  }
  System.out.println("Thread exit");
 }

 public static void main(String[] args) throws InterruptedException {
  Thread thread = new Thread(new InterruptDemo(), "InterruptDemo");

  System.out.println("start thread");
  thread.start();
  Thread.sleep(100);
  System.out.println("interrupt thread");
  thread.interrupt();
  running.set(false);
  System.out.println("main exit");
 }
}

輸出結(jié)果:

start thread
.......
Thread run, total sleep = 0(ms)
interrupt thread
Thread run, total sleep = 0(ms)
Thread run, total sleep = 0(ms)
Thread run, total sleep = 0(ms)
main exit
Thread exit

我們通過使用一個 AtomicBoolean 變量來當(dāng)作標(biāo)志位,使得我們的線程能正常退出。 我們也可以判斷線程是否被中斷而選擇性的退出。

3.4、線程中斷退出

public class InterruptDemo implements Runnable {
 @Override
 public void run() {
  while (!Thread.currentThread().isInterrupted()) {
   long timestamp = System.currentTimeMillis();
   timestamp = System.currentTimeMillis() - timestamp;
   System.out.println("Thread run, total sleep = " + timestamp + "(ms)");
  }
  System.out.println("Thread exit");
 }

 public static void main(String[] args) throws InterruptedException {
  Thread thread = new Thread(new InterruptDemo(), "InterruptDemo");

  System.out.println("start thread");
  thread.start();
  Thread.sleep(100);
  System.out.println("interrupt thread");
  thread.interrupt();
  System.out.println("main exit");
 }
}

輸出結(jié)果:

start thread
.......
Thread run, total sleep = 0(ms)
interrupt thread
Thread run, total sleep = 0(ms)
Thread run, total sleep = 0(ms)
Thread run, total sleep = 0(ms)
main exit
Thread exit

3.5、標(biāo)志位 + 線程中斷結(jié)合

public class InterruptDemo implements Runnable {
 private static final AtomicBoolean running = new AtomicBoolean(true);

 @Override
 public void run() {
  while (running.get()) {
   System.out.println("Thread will sleep 10s ------------------------- running");
   long timestamp = System.currentTimeMillis();
   try {
    Thread.sleep(10000);
   } catch (InterruptedException e) {
    System.out.println("Interrupted... Todo other things then exit......");
    running.set(false);
    continue;
   }
   timestamp = System.currentTimeMillis() - timestamp;
   System.out.println("Thread run, total sleep = " + timestamp + "(ms)");
  }
  System.out.println("Thread exit");
 }

 public static void main(String[] args) throws InterruptedException {
  Thread thread = new Thread(new InterruptDemo(), "InterruptDemo");

  System.out.println("start thread");
  thread.start();
  Thread.sleep(3000);
  System.out.println("interrupt thread");
  thread.interrupt();
  System.out.println("main exit");
 }
}

輸出結(jié)果:

start thread
Thread will sleep 10s ------------------------- running
interrupt thread
main exit
Interrupted... Todo other things then exit......
Thread exit

四、總結(jié)

本文我們分析了線程的中斷,并讓大家了解了中斷的含義:只是告訴該線程,你被『中斷』了,至于你想干嘛,還是由你自己來決定。同時,我們也簡單分析了幾個廢棄的方法的原因。希望大家學(xué)習(xí)了本文之后,能正確且合理的設(shè)計,線程如何安全的退出。

五、附錄

  • Object.wait:阻塞當(dāng)前線程,釋放持有的鎖;
  • Object.notify:喚醒當(dāng)前對象上被阻塞的線程,使其進(jìn)入就緒狀態(tài);
  • Object.notifyAll:喚醒所有線程;
  • Thread.sleep:指定當(dāng)前線程休眠一定時間,讓出CPU,但不會釋放同步資源鎖;
  • Thread.yield:讓出CPU使用權(quán),讓自己和其它線程來爭奪使用CPU的機(jī)會,因此,使用此方法后,并不能保證該線程又再次拿到CPU而恢復(fù)運(yùn)行(使用此方法后,優(yōu)先級高的線程拿到CPU的概率較大,但優(yōu)先級低的線程也有概率拿到CPU而執(zhí)行),同理不會釋放同步資源鎖;

以上就是詳解Java 線程中斷的詳細(xì)內(nèi)容,更多關(guān)于Java 線程中斷的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • MybatisPlus修改時空字段無法修改的解決方案

    MybatisPlus修改時空字段無法修改的解決方案

    這篇文章主要介紹了MybatisPlus修改時空字段無法修改的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java中jar包的生成與使用方式

    java中jar包的生成與使用方式

    這篇文章主要介紹了java中jar包的生成與使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Spring零基礎(chǔ)入門IOC

    Spring零基礎(chǔ)入門IOC

    IoC就是比方說有一個類,我們想要調(diào)用類里面的方法(不是靜態(tài)方法),就要創(chuàng)建該類的對象,使用對象調(diào)用方法來實(shí)現(xiàn)。但對于Spring來說,Spring創(chuàng)建對象的過程,不是在代碼里面實(shí)現(xiàn)的,而是交給Spring來進(jìn)行配置實(shí)現(xiàn)的
    2022-08-08
  • 自定義mybatis插件如何實(shí)現(xiàn)sql日志打印

    自定義mybatis插件如何實(shí)現(xiàn)sql日志打印

    這篇文章主要介紹了自定義mybatis插件如何實(shí)現(xiàn)sql日志打印問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • SpringBoot中使用tkMapper的方法詳解

    SpringBoot中使用tkMapper的方法詳解

    這篇文章主要介紹了SpringBoot中使用tkMapper的方法詳解
    2022-11-11
  • Javaweb監(jiān)聽器實(shí)例之統(tǒng)計在線人數(shù)

    Javaweb監(jiān)聽器實(shí)例之統(tǒng)計在線人數(shù)

    這篇文章主要為大家詳細(xì)介紹了Javaweb監(jiān)聽器實(shí)例之統(tǒng)計在線人數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • Java?Mybatis使用resultMap時,屬性賦值順序錯誤的巨坑

    Java?Mybatis使用resultMap時,屬性賦值順序錯誤的巨坑

    這篇文章主要介紹了Java?Mybatis使用resultMap時,屬性賦值順序錯誤的巨坑,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java?Swing實(shí)現(xiàn)記事本頁面

    Java?Swing實(shí)現(xiàn)記事本頁面

    這篇文章主要為大家詳細(xì)介紹了Java?Swing實(shí)現(xiàn)記事本頁面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Maven的安裝配置詳解

    Maven的安裝配置詳解

    這篇文章主要介紹了Maven的安裝配置詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • java接口語法以及與類的關(guān)系詳解

    java接口語法以及與類的關(guān)系詳解

    接口在JAVA編程語言中是一個抽象類型,是抽象方法的集合,接口通常以interface來聲明。一個類通過繼承接口的方式,從而來繼承接口的抽象方法
    2021-10-10

最新評論

大庆市| 阿拉善左旗| 瓦房店市| 安多县| 卢湾区| 梅河口市| 博白县| 聊城市| 丰宁| 阿鲁科尔沁旗| 高碑店市| 尚义县| 黄龙县| 乐陵市| 长沙县| 杭锦旗| 虞城县| 石嘴山市| 凯里市| 呼伦贝尔市| 库伦旗| 沭阳县| 建阳市| 乌鲁木齐市| 璧山县| 彭水| 时尚| 昆明市| 合川市| 垦利县| 沙坪坝区| 大理市| 星子县| 洛阳市| 安福县| 汾阳市| 扎囊县| 乐安县| 镇宁| 广昌县| 曲水县|