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

詳解JAVA 線程-線程的狀態(tài)有哪些?它是如何工作的?

 更新時(shí)間:2020年06月19日 11:36:40   作者:流年的夏天  
這篇文章主要介紹了詳解JAVA 線程的的相關(guān)資料,文中講解非常細(xì)致,源碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以參考下

線程(Thread)是并發(fā)編程的基礎(chǔ),也是程序執(zhí)行的最小單元,它依托進(jìn)程而存在。

一個(gè)進(jìn)程中可以包含多個(gè)線程,多線程可以共享一塊內(nèi)存空間和一組系統(tǒng)資源,因此線程之間的切換更加節(jié)省資源、更加輕量化,也因此被稱為輕量級(jí)的進(jìn)程。

線程的狀態(tài)在 JDK 1.5 之后以枚舉的方式被定義在 Thread 的源碼中,它總共包含以下 6 個(gè)狀態(tài):

  • NEW,新建狀態(tài),線程被創(chuàng)建出來,但尚未啟動(dòng)時(shí)的線程狀態(tài);
  • RUNNABLE,就緒狀態(tài),表示可以運(yùn)行的線程狀態(tài),它可能正在運(yùn)行,或者是在排隊(duì)等待操作系統(tǒng)給它分配 CPU 資源;
  • BLOCKED,阻塞等待鎖的線程狀態(tài),表示處于阻塞狀態(tài)的線程正在等待監(jiān)視器鎖,比如等待執(zhí)行 synchronized 代碼塊或者使用 synchronized 標(biāo)記的方法;
  • WAITING,等待狀態(tài),一個(gè)處于等待狀態(tài)的線程正在等待另一個(gè)線程執(zhí)行某個(gè)特定的動(dòng)作,比如,一個(gè)線程調(diào)用了 Object.wait() 方法,那它就在等待另一個(gè)線程調(diào)用 Object.notify() 或 Object.notifyAll() 方法;
  • TIMED_WAITING,計(jì)時(shí)等待狀態(tài),和等待狀態(tài)(WAITING)類似,它只是多了超時(shí)時(shí)間,比如調(diào)用了有超時(shí)時(shí)間設(shè)置的方法 Object.wait(long timeout) 和 Thread.join(long timeout) 等這些方法時(shí),它才會(huì)進(jìn)入此狀態(tài);
  • TERMINATED,終止?fàn)顟B(tài),表示線程已經(jīng)執(zhí)行完成。

線程狀態(tài)的源代碼如下:

public enum State {
 /**
  * 新建狀態(tài),線程被創(chuàng)建出來,但尚未啟動(dòng)時(shí)的線程狀態(tài)
  */
 NEW,
 /**
  * 就緒狀態(tài),表示可以運(yùn)行的線程狀態(tài),但它在排隊(duì)等待來自操作系統(tǒng)的 CPU 資源
  */
 RUNNABLE,
 /**
  * 阻塞等待鎖的線程狀態(tài),表示正在處于阻塞狀態(tài)的線程
  * 正在等待監(jiān)視器鎖,比如等待執(zhí)行 synchronized 代碼塊或者
  * 使用 synchronized 標(biāo)記的方法
  */
 BLOCKED,
 /**
  * 等待狀態(tài),一個(gè)處于等待狀態(tài)的線程正在等待另一個(gè)線程執(zhí)行某個(gè)特定的動(dòng)作。
  * 例如,一個(gè)線程調(diào)用了 Object.wait() 它在等待另一個(gè)線程調(diào)用
  * Object.notify() 或 Object.notifyAll()
  */
 WAITING,
 /**
  * 計(jì)時(shí)等待狀態(tài),和等待狀態(tài) (WAITING) 類似,只是多了超時(shí)時(shí)間,比如
  * 調(diào)用了有超時(shí)時(shí)間設(shè)置的方法 Object.wait(long timeout) 和 
  * Thread.join(long timeout) 就會(huì)進(jìn)入此狀態(tài)
  */
 TIMED_WAITING,
 /**
  * 終止?fàn)顟B(tài),表示線程已經(jīng)執(zhí)行完成
  */

}

線程的工作模式是,首先先要?jiǎng)?chuàng)建線程并指定線程需要執(zhí)行的業(yè)務(wù)方法,然后再調(diào)用線程的 start() 方法,此時(shí)線程就從 NEW(新建)狀態(tài)變成了 RUNNABLE(就緒)狀態(tài);

然后線程會(huì)判斷要執(zhí)行的方法中有沒有 synchronized 同步代碼塊,如果有并且其他線程也在使用此鎖,那么線程就會(huì)變?yōu)?BLOCKED(阻塞等待)狀態(tài),當(dāng)其他線程使用完此鎖之后,線程會(huì)繼續(xù)執(zhí)行剩余的方法。

當(dāng)遇到 Object.wait() 或 Thread.join() 方法時(shí),線程會(huì)變?yōu)?WAITING(等待狀態(tài))狀態(tài);

如果是帶了超時(shí)時(shí)間的等待方法,那么線程會(huì)進(jìn)入 TIMED_WAITING(計(jì)時(shí)等待)狀態(tài);

當(dāng)有其他線程執(zhí)行了 notify() 或 notifyAll() 方法之后,線程被喚醒繼續(xù)執(zhí)行剩余的業(yè)務(wù)方法,直到方法執(zhí)行完成為止,此時(shí)整個(gè)線程的流程就執(zhí)行完了,執(zhí)行流程如下圖所示:

【BLOCKED 和 WAITING 的區(qū)別】

雖然 BLOCKED 和 WAITING 都有等待的含義,但二者有著本質(zhì)的區(qū)別。

首先它們狀態(tài)形成的調(diào)用方法不同。

其次 BLOCKED 可以理解為當(dāng)前線程還處于活躍狀態(tài),只是在阻塞等待其他線程使用完某個(gè)鎖資源;

而 WAITING 則是因?yàn)樽陨碚{(diào)用了 Object.wait() 或著是 Thread.join() 又或者是 LockSupport.park() 而進(jìn)入等待狀態(tài),只能等待其他線程執(zhí)行某個(gè)特定的動(dòng)作才能被繼續(xù)喚醒。

比如當(dāng)線程因?yàn)檎{(diào)用了 Object.wait() 而進(jìn)入 WAITING 狀態(tài)之后,則需要等待另一個(gè)線程執(zhí)行 Object.notify() 或 Object.notifyAll() 才能被喚醒。

【start() 和 run() 的區(qū)別】

首先從 Thread 源碼來看,start() 方法屬于 Thread 自身的方法,并且使用了 synchronized 來保證線程安全,源碼如下:

public synchronized void start() {

 // 狀態(tài)驗(yàn)證,不等于 NEW 的狀態(tài)會(huì)拋出異常

 if (threadStatus != 0)

  throw new IllegalThreadStateException();

 // 通知線程組,此線程即將啟動(dòng)

 group.add(this);

 boolean started = false;

 try {

  start0();

  started = true;

 } finally {

  try {

   if (!started) {

    group.threadStartFailed(this);

   }

  } catch (Throwable ignore) {

   // 不處理任何異常,如果 start0 拋出異常,則它將被傳遞到調(diào)用堆棧上

  }

 }

}

run() 方法為 Runnable 的抽象方法,必須由調(diào)用類重寫此方法,重寫的 run() 方法其實(shí)就是此線程要執(zhí)行的業(yè)務(wù)方法,源碼如下:

public class Thread implements Runnable {

 // 忽略其他方法......

 private Runnable target;

 @Override

 public void run() {

  if (target != null) {

   target.run();

  }

 }

}

@FunctionalInterface

public interface Runnable {

 public abstract void run();

}

從執(zhí)行的效果來說,start() 方法可以開啟多線程,讓線程從 NEW 狀態(tài)轉(zhuǎn)換成 RUNNABLE 狀態(tài),而 run() 方法只是一個(gè)普通的方法。

其次,它們可調(diào)用的次數(shù)不同,start() 方法不能被多次調(diào)用,否則會(huì)拋出 java.lang.IllegalStateException;而 run() 方法可以進(jìn)行多次調(diào)用,因?yàn)樗皇且粋€(gè)普通的方法而已。

【線程優(yōu)先級(jí)】

在 Thread 源碼中和線程優(yōu)先級(jí)相關(guān)的屬性有 3 個(gè):

// 線程可以擁有的最小優(yōu)先級(jí)

public final static int MIN_PRIORITY = 1;

// 線程默認(rèn)優(yōu)先級(jí)

public final static int NORM_PRIORITY = 5;

// 線程可以擁有的最大優(yōu)先級(jí)

public final static int MAX_PRIORITY = 10

線程的優(yōu)先級(jí)可以理解為線程搶占 CPU 時(shí)間片的概率,優(yōu)先級(jí)越高的線程優(yōu)先執(zhí)行的概率就越大,但并不能保證優(yōu)先級(jí)高的線程一定先執(zhí)行。

在程序中我們可以通過 Thread.setPriority() 來設(shè)置優(yōu)先級(jí),setPriority() 源碼如下:

public final void setPriority(int newPriority) {

 ThreadGroup g;

 checkAccess();

 // 先驗(yàn)證優(yōu)先級(jí)的合理性

 if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {

  throw new IllegalArgumentException();

 }

 if((g = getThreadGroup()) != null) {

  // 優(yōu)先級(jí)如果超過線程組的最高優(yōu)先級(jí),則把優(yōu)先級(jí)設(shè)置為線程組的最高優(yōu)先級(jí)

  if (newPriority > g.getMaxPriority()) {

   newPriority = g.getMaxPriority();

  }

  setPriority0(priority = newPriority);

 }

}

【線程的常用方法】

線程的常用方法有以下幾個(gè)。

join()

在一個(gè)線程中調(diào)用 other.join() ,這時(shí)候當(dāng)前線程會(huì)讓出執(zhí)行權(quán)給 other 線程,直到 other 線程執(zhí)行完或者過了超時(shí)時(shí)間之后再繼續(xù)執(zhí)行當(dāng)前線程,join() 源碼如下:

public final synchronized void join(long millis)

throws InterruptedException {

 long base = System.currentTimeMillis();

 long now = 0;

 // 超時(shí)時(shí)間不能小于 0

 if (millis < 0) {

  throw new IllegalArgumentException("timeout value is negative");

 }

 // 等于 0 表示無限等待,直到線程執(zhí)行完為之

 if (millis == 0) {

  // 判斷子線程 (其他線程) 為活躍線程,則一直等待

  while (isAlive()) {

   wait(0);

  }

 } else {

  // 循環(huán)判斷

  while (isAlive()) {

   long delay = millis - now;

   if (delay <= 0) {

    break;

   }

   wait(delay);

   now = System.currentTimeMillis() - base;

  }

 }

}

從源碼中可以看出 join() 方法底層還是通過 wait() 方法來實(shí)現(xiàn)的。

例如,在未使用 join() 時(shí),代碼如下:

public class ThreadExample {

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

  Thread thread = new Thread(() -> {

   for (int i = 1; i < 6; i++) {

    try {

     Thread.sleep(1000);

    } catch (InterruptedException e) {

     e.printStackTrace();

    }

    System.out.println("子線程睡眠:" + i + "秒。");

   }

  });

  thread.start(); // 開啟線程

  // 主線程執(zhí)行

  for (int i = 1; i < 4; i++) {

   try {

    Thread.sleep(1000);

   } catch (InterruptedException e) {

    e.printStackTrace();

   }

   System.out.println("主線程睡眠:" + i + "秒。");

  }

 }

}

程序執(zhí)行結(jié)果為:

復(fù)制主線程睡眠:1秒。

子線程睡眠:1秒。

主線程睡眠:2秒。

子線程睡眠:2秒。

主線程睡眠:3秒。

子線程睡眠:3秒。

子線程睡眠:4秒。

子線程睡眠:5秒。

從結(jié)果可以看出,在未使用 join() 時(shí)主子線程會(huì)交替執(zhí)行。

然后我們?cè)侔?join() 方法加入到代碼中,代碼如下:

public class ThreadExample {

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

  Thread thread = new Thread(() -> {

   for (int i = 1; i < 6; i++) {

    try {

     Thread.sleep(1000);

    } catch (InterruptedException e) {

     e.printStackTrace();

    }

    System.out.println("子線程睡眠:" + i + "秒。");

   }

  });

  thread.start(); // 開啟線程

  thread.join(2000); // 等待子線程先執(zhí)行 2 秒鐘

  // 主線程執(zhí)行

  for (int i = 1; i < 4; i++) {

   try {

    Thread.sleep(1000);

   } catch (InterruptedException e) {

    e.printStackTrace();

   }

   System.out.println("主線程睡眠:" + i + "秒。");

  }

 }

}

程序執(zhí)行結(jié)果為:

復(fù)制子線程睡眠:1秒。

子線程睡眠:2秒。

主線程睡眠:1秒。

// thread.join(2000); 等待 2 秒之后,主線程和子線程再交替執(zhí)行

子線程睡眠:3秒。

主線程睡眠:2秒。

子線程睡眠:4秒。

子線程睡眠:5秒。

主線程睡眠:3秒。

從執(zhí)行結(jié)果可以看出,添加 join() 方法之后,主線程會(huì)先等子線程執(zhí)行 2 秒之后才繼續(xù)執(zhí)行。

yield()

看 Thread 的源碼可以知道 yield() 為本地方法,也就是說 yield() 是由 C 或 C++ 實(shí)現(xiàn)的,源碼如下:

public static native void yield();

yield() 方法表示給線程調(diào)度器一個(gè)當(dāng)前線程愿意出讓 CPU 使用權(quán)的暗示,但是線程調(diào)度器可能會(huì)忽略這個(gè)暗示。

比如我們執(zhí)行這段包含了 yield() 方法的代碼,如下所示:

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

 Runnable runnable = new Runnable() {

  @Override

  public void run() {

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

    System.out.println("線程:" +

      Thread.currentThread().getName() + " I:" + i);

    if (i == 5) {

     Thread.yield();

    }

   }

  }

 };

 Thread t1 = new Thread(runnable, "T1");

 Thread t2 = new Thread(runnable, "T2");

 t1.start();

 t2.start();

}

當(dāng)我們把這段代碼執(zhí)行多次之后會(huì)發(fā)現(xiàn),每次執(zhí)行的結(jié)果都不相同,這是因?yàn)?yield() 執(zhí)行非常不穩(wěn)定,線程調(diào)度器不一定會(huì)采納 yield() 出讓 CPU 使用權(quán)的建議,從而導(dǎo)致了這樣的結(jié)果。

以上就是詳解JAVA 線程-線程的狀態(tài)有哪些?它是如何工作的?的詳細(xì)內(nèi)容,更多關(guān)于java 線程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 在dos窗口中編譯和運(yùn)行java文件的方法

    在dos窗口中編譯和運(yùn)行java文件的方法

    這篇文章主要介紹了在dos窗口中編譯和運(yùn)行java文件的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Java Object類詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java Object類詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java作為一個(gè)龐大的知識(shí)體系,涉及到的知識(shí)點(diǎn)繁多,本文將從Java中最基本的類java.lang.Object開始談起,對(duì)java object類相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧
    2017-04-04
  • 一篇文章從無到有詳解Spring中的AOP

    一篇文章從無到有詳解Spring中的AOP

    。Spring AOP 是基于 AOP 編程模式的一個(gè)框架,它的使用有效減少了系統(tǒng)間的重復(fù)代碼,達(dá)到了模塊間的松耦合目的,這篇文章主要給大家介紹了關(guān)于Spring中AOP的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • Java使用jmeter進(jìn)行壓力測試

    Java使用jmeter進(jìn)行壓力測試

    本篇文章簡單講一下使用jmeter進(jìn)行壓力測試。其壓測思想就是 通過創(chuàng)建指定數(shù)量的線程,同時(shí)請(qǐng)求指定接口,來模擬指定數(shù)量用戶同時(shí)進(jìn)行某個(gè)操作的場景,感興趣的小伙伴們可以參考一下
    2021-07-07
  • 解決springboot引入swagger2不生效問題

    解決springboot引入swagger2不生效問題

    這篇文章主要為大家介紹了解決springboot引入swagger2不生效問題的方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Gauva使用ListenableFuture介紹說明

    Gauva使用ListenableFuture介紹說明

    并發(fā)是一個(gè)困難問題,但是通過強(qiáng)大和強(qiáng)大的抽象能夠顯著的簡化工作。為了簡化問題,Gauva使用ListenableFuture擴(kuò)展了JDK的Future接口,這篇文章主要介紹了Gauva使用ListenableFuture
    2023-01-01
  • SpringBoot之自定義Filter獲取請(qǐng)求參數(shù)與響應(yīng)結(jié)果案例詳解

    SpringBoot之自定義Filter獲取請(qǐng)求參數(shù)與響應(yīng)結(jié)果案例詳解

    這篇文章主要介紹了SpringBoot之自定義Filter獲取請(qǐng)求參數(shù)與響應(yīng)結(jié)果案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • 如何關(guān)閉 IDEA 自動(dòng)更新

    如何關(guān)閉 IDEA 自動(dòng)更新

    這篇文章主要介紹了如何關(guān)閉 IDEA 自動(dòng)更新,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • java中利用棧實(shí)現(xiàn)字符串回文算法

    java中利用棧實(shí)現(xiàn)字符串回文算法

    給定一個(gè)由多個(gè)a和b組成的字符串?dāng)?shù)組,字符串中有一個(gè)特殊的字符X,位于字符串的正中間,例如(aaaabbbbXabaabbbb),如何判定該字符串是否回文
    2020-12-12
  • 利用spring-boot-maven-plugin插件打包SpringBoot應(yīng)用方式

    利用spring-boot-maven-plugin插件打包SpringBoot應(yīng)用方式

    spring-boot-maven-plugin插件可以將SpringBoot應(yīng)用打成帶依賴的jar包,該包中不僅包含應(yīng)用自身的代碼,還包含了pom.xml中配置的依賴,修改pom.xml打包后,生成的jar包就包含了項(xiàng)目依賴,生成的jar包位于項(xiàng)目的target文件夾下
    2025-02-02

最新評(píng)論

竹溪县| 塘沽区| 黄梅县| 南皮县| 余姚市| 潮州市| 吉木乃县| 闸北区| 无棣县| 宁都县| 淅川县| 尉氏县| 林口县| 汾西县| 门头沟区| 密云县| 宁河县| 武隆县| 陕西省| 沭阳县| 博野县| 融水| 贞丰县| 揭西县| 集贤县| 繁峙县| 同仁县| 大足县| 黄骅市| 凤冈县| 北宁市| 鹤山市| 霍林郭勒市| 武城县| 台中县| 内黄县| 延庆县| 张家界市| 牙克石市| 宝兴县| 永吉县|