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

Java線程狀態(tài)及切換、關(guān)閉線程的正確姿勢分享

 更新時間:2019年10月18日 08:32:47   作者:張小云的博客  
這篇文章主要給大家介紹了關(guān)于Java線程狀態(tài)及切換、關(guān)閉線程的正確姿勢,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

前言

在講線程之前有必要討論一下進程的定義:進程是程序在一個數(shù)據(jù)集合上運行的過程,它是系統(tǒng)進行資源分配和調(diào)度的一個獨立單位。進程實體由程序段, 數(shù)據(jù)段 PCB(進程控制塊)組成。線程又是什么?線程可以看做輕量級進程,線程是進程的執(zhí)行單元,是進程調(diào)度的基本單位

本文將詳細(xì)介紹關(guān)于Java線程狀態(tài)及切換、關(guān)閉線程的相關(guān)內(nèi)容,下面話不多說了,來一起看看詳細(xì)的介紹吧

1、線程狀態(tài)及切換

Java中的線程有六種狀態(tài),使用線程Thread內(nèi)的枚舉類來實現(xiàn),如下,我對每個狀態(tài)都進行了一定的解釋。

public enum State {
  /** 表示一個線程還沒啟用(即未調(diào)用start方法)*/
  NEW,

  /**
   * JVM中執(zhí)行的線程都是處于這個狀態(tài)的,但是處于這個狀態(tài)不一定在JVM中執(zhí)行,
   * 也就是說,只有這個狀態(tài)有資格被JVM調(diào)度從而獲得時間片執(zhí)行。
   */
  RUNNABLE,

  /**
   * 線程在等待獲取鎖資源從而進入阻塞狀態(tài),
   * 在這個狀態(tài)中,其一直監(jiān)視鎖的動態(tài),隨時準(zhǔn)備搶占鎖
   * 若獲得鎖資源,重新進入RUNNABLE狀態(tài)
   */
  BLOCKED,

  /**
   * 當(dāng)調(diào)用Object.wait、Thread.join或者LockSupport類的park方法的時候,線程進入此狀態(tài),
   * 該狀態(tài)若無其他線程主動喚醒,則無期限的等待。
   * 喚醒的方法包括:Object.notify(喚醒隨機一個)、Object.notifyAll(喚醒全部線程),
   * 被喚醒的線程重新進入RUNNABLE狀態(tài)
   */
  WAITING,

  /**
   * 同WAITING狀態(tài),不過不同的是調(diào)用的方法加上了時間的限制,
   * 例如:Object.wait(10)、Thread.sleep(10)、Thread.join(10)、LockSupport.parkNanos(10)、LockSupport.parkUntil(10)這些方法
   * 喚醒的方法有兩種:
   *  1、時間過期。
   *  2、其他線程調(diào)用了notify或者notifyAll
   * 喚醒之后同樣進入RUNNABLE狀態(tài)
   */
  TIMED_WAITING,

  /** 線程的終點(正常死亡或者被終止)*/
  TERMINATED;
 }

除了NEW和TERMINATED之外,其他的狀態(tài)都是可以相互轉(zhuǎn)換的,其轉(zhuǎn)換過程如下圖所示

這里特別講一下RUNNABLE狀態(tài),在這個狀態(tài)中線程并不一定在執(zhí)行程序,只有被JVM調(diào)度的線程才能獲得執(zhí)行的時間片,并且只有這個狀態(tài)的線程才能夠獲得時間片,換句話說,被JVM調(diào)度并且獲得時間片是只屬于處于RUNNABLE狀態(tài)線程的權(quán)利。為了便于理解,可以將RUNNABLE分成Runnable和Running兩個狀態(tài)(當(dāng)然,你也可以換成其他的,這里我只是自己好理解),那么上面的線程轉(zhuǎn)換圖就轉(zhuǎn)變成了下面這樣(參考《Java并發(fā)編程的藝術(shù)》中的線程狀態(tài)圖):

關(guān)于線程狀態(tài)轉(zhuǎn)換的例子,可以通過下面的代碼加深理解

public class Test {
 public static void main(String[] args) {
  Test test = new Test();
  // 1.NEW狀態(tài)
  Thread thread = new Thread(() -> {
   // 3.進行test對象鎖的爭奪,若搶到鎖則繼續(xù)執(zhí)行,否則進入BLOCKED狀態(tài)監(jiān)控該鎖,重新獲得后進入RUNNABLE 
   synchronized (test) {
    try {
     // 4.進入TIMED_WAITING狀態(tài),100ms后重新進入RUNNABLE狀態(tài)爭奪時間片 
     Thread.sleep(100);
     // 5.重新獲得時間片之后,進入WAITING狀態(tài) 
     test.wait();
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
   // 6.正常run()方法執(zhí)行完畢后線程結(jié)束,進入TERMINATED 
  });
  // 2.調(diào)用start()方法,線程進入RUNNABLE狀態(tài)
  thread.start();
 }
}

注:代碼執(zhí)行的順序為注釋的序號

2、正確的結(jié)束一個線程

在上面的例子中我們看到線程的run方法正常執(zhí)行完畢之后線程就正常死亡進入TERMINATED狀態(tài)了,那么如果我們有中途停止線程的需求,我們應(yīng)該如何正確的結(jié)束一個線程呢?

使用interrupt()方法:在線程內(nèi)部,其定義了一個變量來標(biāo)識當(dāng)前線程是否處于被打斷狀態(tài),調(diào)用interrupt()方法則使這個狀態(tài)變?yōu)閠rue。我們采用這個方法加異常處理的方式來結(jié)束一個線程。

  public static void main(String[] args) {
  Thread thread = new Thread(() -> {
   try {
    Thread.sleep(1);
   } catch (InterruptedException e) {
    e.printStackTrace();
    // 這里的return是必須的,原因后面說明
    return;
   }
   System.err.println("thread interrupt test...");
  });
  thread.start();
  thread.interrupt();
  System.out.println("main thread end...");
 }

// 結(jié)果圖:異常后面的語句不會打印

  這里關(guān)于線程中的打斷標(biāo)識變量(之后以interrupt稱)需要說明的是,在特定的情況下其狀態(tài)會被重置。

   1、線程內(nèi)部在catch了異常了之后interrupt的狀態(tài)會被重置為false。

2、線程調(diào)用了Thread.interrupted()方法之后,interrupt的狀態(tài)會被重置為false。如果需要判斷線程是否中斷的話可以使用對象方法isInterrupted(),此方法不會重置。

所以在剛才的代碼中需要加入return來結(jié)束線程,否則的話線程還是會繼續(xù)往下執(zhí)行,如下圖


使用isInterrupted()實現(xiàn):

public static void main(String[] args) throws InterruptedException {
 Thread thread = new Thread(() -> {
  while (!Thread.currentThread().isInterrupted()) {
   int k = 0;
   while (k++ < 10) {
    System.out.println("do something..." + k);
   }
  }
 System.err.println("thread end...");
 });
 thread.start();
 Thread.sleep(1);
 // 主線程流程執(zhí)行完了,需要停止線程
 thread.interrupt();
}

使用標(biāo)識位來實現(xiàn):定義一個變量標(biāo)識線程是否終止,若終止了則退出run方法。跟上面isInterrupted()的實現(xiàn)一樣,不過換成了volatile變量而已。

public class Test {

 public static volatile boolean interrupted = false;

 public static void main(String[] args) throws InterruptedException {
  Thread thread = new Thread(() -> {
   while (!interrupted) {
    int k = 0;
    while (k++ < 10) {
     if (interrupted) {
      System.err.println("thread invoke end....");
      return;
     }
     System.out.println("do something..." + k);
    }
   }
  System.err.println("thread end...");
  });
  thread.start();
  Thread.sleep(1);
  // 主線程流程執(zhí)行完了,需要停止線程
  interrupted = true;
 }
}
// 結(jié)果圖

 stop()方法——不正確的線程中斷方法

   在線程提供的方法中還有一個方法可以強制關(guān)閉線程——stop()。這個方法可以說是相當(dāng)?shù)陌缘溃o人一種“我不管,我就是要你現(xiàn)在立刻死亡(指線程)”的感覺,并且其還會釋放線程所有的鎖資源,這樣可能會導(dǎo)致出現(xiàn)數(shù)據(jù)不一致從而出現(xiàn)線程不安全的情況,如下面例子。

public class Test {

  public static volatile boolean flag = false;
  public int state = 0;

  public static void main(String[] args) throws InterruptedException {
   Test test = new Test();
   Thread thread = new Thread(() -> {
    synchronized (test) {
     try {
      test.state = 1;
      Thread.sleep(100);
      if (flag) {
       test.state = 2;
      }
      System.err.println("thread execute finished...");
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   });
   thread.start();
   Thread.sleep(1);
   thread.stop();
   flag = true;
   System.out.println("state狀態(tài):" + test.state);
  }
}
// 在這段代碼中,進入線程時默認(rèn)將state賦為1,接著過一段時間后如果觸發(fā)了特定條件則把state賦為2,但是在特定條件觸發(fā)之前,線程就被終止掉了,這個特定條件雖然符合但卻沒辦法執(zhí)行,從而導(dǎo)致數(shù)據(jù)的不一致。
// 結(jié)果圖


所以,我們應(yīng)該采用上面兩種正確的方式而不是stop()來中止線程。此外,stop()方法若在線程start()之前執(zhí)行,那么在線程啟動的時候就會立即死亡。

若有不對之處,望各位不吝指教(反正免費,對吧)。

總結(jié)

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

相關(guān)文章

  • springboot基于IDEA環(huán)境熱加載與熱部署教程

    springboot基于IDEA環(huán)境熱加載與熱部署教程

    這篇文章主要為大家介紹了springboot在IDEA環(huán)境下的熱加載與熱部署教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03
  • Java8進行多個字段分組統(tǒng)計的實例代碼

    Java8進行多個字段分組統(tǒng)計的實例代碼

    在本篇文章里小編給大家分享的是關(guān)于Java8進行多個字段分組統(tǒng)計的實例代碼,需要的朋友們可以學(xué)習(xí)下。
    2020-05-05
  • java中的executeQuery()方法使用

    java中的executeQuery()方法使用

    這篇文章主要介紹了java中的executeQuery()方法使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java實現(xiàn)跳躍表的示例詳解

    Java實現(xiàn)跳躍表的示例詳解

    跳表全稱叫做跳躍表,簡稱跳表,是一個隨機化的數(shù)據(jù)結(jié)構(gòu),實質(zhì)就是一種可以進行二分查找的有序鏈表。本文將利用Java語言編寫一個跳表,需要的可以參考一下
    2022-05-05
  • idea 隱藏target,iml等不需要展示的文件(推薦)

    idea 隱藏target,iml等不需要展示的文件(推薦)

    這篇文章主要介紹了idea 隱藏target,iml等不需要展示的文件,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • java使用RSA加密方式實現(xiàn)數(shù)據(jù)加密解密的代碼

    java使用RSA加密方式實現(xiàn)數(shù)據(jù)加密解密的代碼

    這篇文章給大家分享java使用RSA加密方式實現(xiàn)數(shù)據(jù)加密解密,通過實例代碼文字相結(jié)合給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友參考下
    2019-11-11
  • 3行代碼快速實現(xiàn)Spring Boot Oauth2服務(wù)功能

    3行代碼快速實現(xiàn)Spring Boot Oauth2服務(wù)功能

    oauthserver是一個基于Spring Boot Oauth2的完整的獨立的Oauth服務(wù)器。僅僅需要創(chuàng)建相關(guān)數(shù)據(jù)表,修改數(shù)據(jù)庫的連接信息,你就可以得到一個Oauth服務(wù)器。這篇文章給大家介紹3行代碼快速實現(xiàn)Spring Boot Oauth2服務(wù)功能,需要的朋友參考下吧
    2018-04-04
  • Java構(gòu)造器使用方法及注意事項

    Java構(gòu)造器使用方法及注意事項

    這篇文章主要介紹了Java構(gòu)造器使用方法及注意事項的相關(guān)資料,這里舉例說明如何使用構(gòu)造器及需要注意的地方,需要的朋友可以參考下
    2017-07-07
  • Java Fluent Mybatis 分頁查詢與sql日志輸出詳解流程篇

    Java Fluent Mybatis 分頁查詢與sql日志輸出詳解流程篇

    Java中常用的ORM框架主要是mybatis, hibernate, JPA等框架。國內(nèi)又以Mybatis用的多,基于mybatis上的增強框架,又有mybatis plus和TK mybatis等。今天我們介紹一個新的mybatis增強框架 fluent mybatis關(guān)于分頁查詢、sql日志輸出流程
    2021-10-10
  • RestTemplate設(shè)置超時時間及返回狀態(tài)碼非200處理

    RestTemplate設(shè)置超時時間及返回狀態(tài)碼非200處理

    這篇文章主要為大家介紹了RestTemplate設(shè)置超時時間及返回狀態(tài)碼非200處理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06

最新評論

德清县| 峨山| 西乌珠穆沁旗| 屏东市| 新邵县| 吉木乃县| 淮滨县| 淄博市| 宁都县| 江口县| 平山县| 育儿| 闸北区| 沙湾县| 万山特区| 陕西省| 青岛市| 涿鹿县| 米脂县| 怀宁县| 盘山县| 拜城县| 鄯善县| 禄丰县| 普陀区| 鲁山县| 区。| 永州市| 封开县| 晋江市| 龙川县| 景宁| 广水市| 家居| 巴彦县| 庐江县| 克拉玛依市| 通辽市| 文成县| 无锡市| 华坪县|