Java線程狀態(tài)及其轉(zhuǎn)換

線程狀態(tài)及其轉(zhuǎn)換

一勋锤、線程狀態(tài)

Java中定義線程的狀態(tài)有6種,可以查看Thread類的State枚舉:

public static enum State
  {
    NEW,  RUNNABLE,  BLOCKED,  WAITING,  TIMED_WAITING,  TERMINATED;
    
    private State() {}
  }
  1. 初始(NEW):新創(chuàng)建了一個(gè)線程對(duì)象侥祭,還沒(méi)調(diào)用start方法叁执;
  2. 運(yùn)行(RUNNABLE):java線程中將就緒(ready)和運(yùn)行中(running)統(tǒng)稱為運(yùn)行(RUNNABLE)。線程創(chuàng)建后調(diào)用了該對(duì)象的start方法矮冬,此時(shí)處于就緒狀態(tài)谈宛,當(dāng)獲得CPU時(shí)間片后變?yōu)檫\(yùn)行中狀態(tài);
  3. 阻塞(BLOCKED):表現(xiàn)線程阻塞于鎖胎署;
  4. 等待(WAITING):進(jìn)入該狀態(tài)的線程需要等待其他線程做出一些特定動(dòng)作(通知或中斷)吆录;
  5. 超時(shí)等待(TIMED_WAITING):該狀態(tài)不同于WAITING,它可以在指定時(shí)間后自行返回琼牧;
  6. 終止(TERMINATED):表示該線程已經(jīng)執(zhí)行完畢恢筝。

二哀卫、線程狀態(tài)轉(zhuǎn)換

來(lái)看一張線程狀態(tài)轉(zhuǎn)換圖:

線程狀態(tài)轉(zhuǎn)換.png

下面從代碼實(shí)例看線程的各個(gè)狀態(tài):

2.1 超時(shí)等待

public class Test {
    public static void main(String[] args) throws Exception {
        System.out.println("start");
        Thread.sleep(100000);
        System.out.println("end");
    }
}

通過(guò)Java VisualVM打印線程dump可以看到此線程處于TIMED_WAITING狀態(tài):

...
"main" #1 prio=5 os_prio=0 tid=0x00000000055b3800 nid=0x4e8c waiting on condition [0x000000000558f000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at Test.main(Test.java:4)

   Locked ownable synchronizers:
        - None
...

2.2 等待

public class Test {
    public static void main(String[] args) throws Exception {
        Thread1 t = new Thread1();
        t.start();
        t.join();
    }
    
    static class Thread1 extends Thread {
        @Override
        public void run() {
            System.out.println("start");
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {}
            System.out.println("end");
        }
    }
}

同樣通過(guò)線程dump可以看到主線程處于WAITING狀態(tài),子線程處于TIMED_WAITING狀態(tài):

...
"Thread-0" #11 prio=5 os_prio=0 tid=0x0000000020bf7000 nid=0x4f94 waiting on condition [0x000000002189f000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at Test$Thread1.run(Test.java:13)

   Locked ownable synchronizers:
        - None
...
"main" #1 prio=5 os_prio=0 tid=0x0000000004f63800 nid=0x431c in Object.wait() [0x0000000004eef000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076b6e0898> (a Test$Thread1)
        at java.lang.Thread.join(Unknown Source)
        - locked <0x000000076b6e0898> (a Test$Thread1)
        at java.lang.Thread.join(Unknown Source)
        at Test.main(Test.java:5)

   Locked ownable synchronizers:
        - None
...

下面演示wait方法導(dǎo)致的等待狀態(tài):

public class Test {
    public static int i = 0;
    public static void main(String[] args) throws Exception {
        Thread1 t = new Thread1();
        t.start();
        synchronized (t) {
            System.out.println("等待子線程");
            t.wait();
        }
        System.out.println("主線程結(jié)束");
    }
    
    static class Thread1 extends Thread {
        @Override
        public void run() {
            synchronized (this) {
                for (int i = 0; i < 10; i++) {
                    try {
                        System.out.println(i);
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
                notify();
            }
        }
    }
    
}

通過(guò)線程堆棧觀察撬槽,主線程同樣處于等待WAITING狀態(tài):

...
"main" #1 prio=5 os_prio=0 tid=0x0000000005983800 nid=0xb54 in Object.wait() [0x00000000058df000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076b6e0aa8> (a Test$Thread1)
        at java.lang.Object.wait(Unknown Source)
        at Test.main(Test.java:8)
        - locked <0x000000076b6e0aa8> (a Test$Thread1)

   Locked ownable synchronizers:
        - None
...

2.3 阻塞

public class Test {
    public static void main(String[] args) throws Exception {
        Thread1 t = new Thread1();
        t.start();
        test();
    }
    
    static class Thread1 extends Thread {
        @Override
        public void run() {
            test();
        }
    }
    
    static synchronized void test() {
        System.out.println(Thread.currentThread().getName() + " -- start");
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {}
        System.out.println(Thread.currentThread().getName() + " -- end");
    }
}

通過(guò)線程dump可以看到子線程處于阻塞(BLOCKED)狀態(tài)此改,主線程處于超時(shí)等待(TIMED_WAITING)狀態(tài):

...
"Thread-0" #11 prio=5 os_prio=0 tid=0x0000000020ef1800 nid=0x4df4 waiting for monitor entry [0x0000000021b9f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at Test.test(Test.java:16)
        - waiting to lock <0x000000076b6dea88> (a java.lang.Class for Test)
        at Test$Thread1.run(Test.java:11)

   Locked ownable synchronizers:
        - None
...
"main" #1 prio=5 os_prio=0 tid=0x00000000051e3800 nid=0x3ee8 waiting on condition [0x000000000517f000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at Test.test(Test.java:18)
        - locked <0x000000076b6dea88> (a java.lang.Class for Test)
        at Test.main(Test.java:5)

   Locked ownable synchronizers:
        - None
...

三、幾種方法的對(duì)比

  1. Thead.sleep(long millis):一定是當(dāng)前線程調(diào)用此方法侄柔,當(dāng)前線程進(jìn)入TIMED_WAITING狀態(tài)带斑,但不釋放對(duì)象鎖,millis后線程自動(dòng)蘇醒進(jìn)入就緒狀態(tài)勋拟。作用:給其它線程執(zhí)行機(jī)會(huì)的最佳方式勋磕。
  2. Thread.yield():一定是當(dāng)前線程調(diào)用此方法,當(dāng)前線程放棄獲取的CPU時(shí)間片敢靡,但不釋放鎖資源挂滓,由運(yùn)行狀態(tài)變?yōu)榫途w狀態(tài),讓OS再次選擇線程啸胧。作用:讓相同優(yōu)先級(jí)的線程輪流執(zhí)行赶站,但并不保證一定會(huì)輪流執(zhí)行。實(shí)際中無(wú)法保證yield()達(dá)到讓步目的纺念,因?yàn)樽尣降木€程還有可能被線程調(diào)度程序再次選中贝椿。Thread.yield()不會(huì)導(dǎo)致阻塞。該方法與sleep()類似陷谱,只是不能由用戶指定暫停多長(zhǎng)時(shí)間烙博。
  3. obj.join()/obj.join(long millis):當(dāng)前線程里調(diào)用其它線程T的join方法,當(dāng)前線程進(jìn)入WAITING/TIMED_WAITING狀態(tài)烟逊,當(dāng)前線程不會(huì)釋放已經(jīng)持有的對(duì)象鎖渣窜。線程T執(zhí)行完畢或者millis時(shí)間到,當(dāng)前線程一般情況下進(jìn)入RUNNABLE狀態(tài)宪躯,也有可能進(jìn)入BLOCKED狀態(tài)(因?yàn)閖oin是基于wait實(shí)現(xiàn)的)乔宿。
  4. obj.wait()/obj.wait(long millis):當(dāng)前線程調(diào)用對(duì)象的wait()方法,當(dāng)前線程釋放對(duì)象鎖访雪,進(jìn)入等待隊(duì)列详瑞。依靠notify()/notifyAll()喚醒或者wait(long timeout) timeout時(shí)間到自動(dòng)喚醒。
  5. obj.notify():?jiǎn)拘言诖藢?duì)象監(jiān)視器上等待的單個(gè)線程臣缀,選擇是任意性的坝橡。notifyAll()喚醒在此對(duì)象監(jiān)視器上等待的所有線程。notify肝陪,notifyAll和wait一起使用驳庭,用于協(xié)調(diào)多個(gè)線程對(duì)共享數(shù)據(jù)的存取刑顺,所以必須在synchronized語(yǔ)句塊內(nèi)使用氯窍,也就是說(shuō)饲常,調(diào)用wait(),notify()和notifyAll()的任務(wù)在調(diào)用這些方法前必須擁有對(duì)象的鎖狼讨。
  6. LockSupport.park()/LockSupport.parkNanos(long nanos),LockSupport.parkUntil(long deadlines):當(dāng)前線程進(jìn)入WAITING/TIMED_WAITING狀態(tài)贝淤。對(duì)比wait方法,不需要獲得鎖就可以讓線程進(jìn)入WAITING/TIMED_WAITING狀態(tài),需要通過(guò)LockSupport.unpark(Thread thread)喚醒政供。

參考:

Java線程的6種狀態(tài)及切換:https://blog.csdn.net/pange1991/article/details/53860651

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末播聪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子布隔,更是在濱河造成了極大的恐慌离陶,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衅檀,死亡現(xiàn)場(chǎng)離奇詭異招刨,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)哀军,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門沉眶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人杉适,你說(shuō)我怎么就攤上這事谎倔。” “怎么了猿推?”我有些...
    開(kāi)封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵片习,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蹬叭,道長(zhǎng)毯侦,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任具垫,我火速辦了婚禮侈离,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筝蚕。我一直安慰自己卦碾,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布起宽。 她就那樣靜靜地躺著洲胖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坯沪。 梳的紋絲不亂的頭發(fā)上绿映,一...
    開(kāi)封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼叉弦。 笑死丐一,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的淹冰。 我是一名探鬼主播库车,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼樱拴!你這毒婦竟也來(lái)了柠衍?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤晶乔,失蹤者是張志新(化名)和其女友劉穎珍坊,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體正罢,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垫蛆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腺怯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袱饭。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖呛占,靈堂內(nèi)的尸體忽然破棺而出虑乖,到底是詐尸還是另有隱情,我是刑警寧澤晾虑,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布疹味,位于F島的核電站,受9級(jí)特大地震影響帜篇,放射性物質(zhì)發(fā)生泄漏糙捺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一笙隙、第九天 我趴在偏房一處隱蔽的房頂上張望洪灯。 院中可真熱鬧,春花似錦竟痰、人聲如沸签钩。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)铅檩。三九已至,卻和暖如春莽鸿,著一層夾襖步出監(jiān)牢的瞬間昧旨,已是汗流浹背拾给。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兔沃,地道東北人蒋得。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像粘拾,于是被迫代替她去往敵國(guó)和親窄锅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子创千,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容