Java併發編程初級篇(三):線程狀態以及狀態轉換過程

線程狀態:java

  • NEW:當一個線程被建立之初,那麼此時線程就是新生狀態,此狀態下線程已經分配完畢內存空間。
  • RUNNABLE:當調用Thread.start()方法後,線程進入就緒狀態,此時線程並不會立刻開始執行。須要等待JVM選中並分配CPU時間才能開始執行。
  • RUNNING:線程被分配CPU時間後,進入執行狀態,在此狀態下會運行run()方法中定義的代碼。
  • BLOCKED:當處於運行狀態的線程,調用一個被阻塞的方法;試圖獲取一個正在被其餘線程佔用的鎖,都會進入阻塞狀態。
  • WAITING:等待狀態。當調用了Object.wait()Thread.join()LockSupport.park();方法後線程會進入等待狀態。調用Object.wait()的線程會等待Object.notify()方法的調用而從新進入就緒狀態。調用Thread.join()方法的線程會等待調用方法線程執行結束而進入結束狀態。
  • TIMED_WAITING:固定時間等待狀態。此狀態下的線程都有一個固定的等待時間,經過調用Object.wait(Long)Thread.sleep(Long)Thread.join(Long),都會讓線程進入此狀態。處於此狀態的線程會等待指定的時間,而後恢復執行。
  • TERMINATED:線程執行結束。

狀態轉換圖:ide

線程狀態轉換函數:函數

  • new Thread():線程建立之初,線程狀態爲初始狀態NEW。
  • Thread.start():線程狀態爲RUNNABLE,等待JVM分配CUP時間來執行。
  • Thread.sleep(long):線程進入TIMED_WAITING狀態,不釋放線程持有的鎖,會釋放計算資源,並等待指定時間後恢復。
  • Object.wait()/Objectwait(long):前者線程進入WAITING狀態,並等待被喚醒;後者線程進入TIMED_WAITING,等待指定時間後恢復。可是wait()方法與sleep()方法不一樣,它會釋放線程持有的鎖。
  • Thread.join()/Thread.join(long):前者線程進入WAITING狀態,並等待加入的線程執行完畢後恢復;後者線程進入TIMED_WAITING,等待指定時間後恢復。
  • synchronized:等待獲取鎖會使線程進入BLOCKED狀態,並一直競爭這個鎖,知道獲取鎖後進入同步塊方法,並恢復RUNNABLE狀態。

狀態轉換示例:oop

定義一個WaitRunnable線程對象,在run()方法中加鎖並調用wait()方法模擬等待資源。線程

public class WaitRunnable implements Runnable{
    @Override
    public void run() {
        System.out.printf("%s:開始執行,準備鎖定object。\n", Thread.currentThread().getName());
        synchronized (Main.object) {
            try {
                System.out.printf("%s:成功鎖定object,執行同步模塊。\n", Thread.currentThread().getName());
                Thread.sleep(3000);
                System.out.printf("%s:被掛起,等待其餘線程喚醒本身。\n", Thread.currentThread().getName());
                Main.object.wait();
                System.out.printf("%s: 被喚起,繼續開始執行。\n", Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.printf("%s: 執行結束。", Thread.currentThread().getName());
    }
}

定義一個NotifyRunnable線程對象,在run()方法中加鎖,並調用notify()方法來喚醒WaitRunnable線程。日誌

package oschian.section_03;

/**
 * Created by hadoop on 2016/11/22.
 */
public class NotifyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.printf("%s:開始執行,準備鎖定object。\n", Thread.currentThread().getName());
        synchronized (Main.object) {
            System.out.printf("%s:成功鎖定object,執行同步模塊。\n", Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.printf("%s: 喚醒其餘線程。\n", Thread.currentThread().getName());
            Main.object.notify();
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.printf("%s: 執行結束。\n", Thread.currentThread().getName());
    }
}

定義主方法類,啓動兩個線程,並打印線程狀態。code

public class Main {
    public static final Object object = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new WaitRunnable());
        Thread thread2 = new Thread(new NotifyRunnable());

        System.out.printf("Main: %s:%s , %s:%s\n", thread1.getName(), thread1.getState(), thread2.getName(), thread2.getState());

        thread1.start();
        thread2.start();

        while (thread1.getState() != Thread.State.TERMINATED
                || thread2.getState() != Thread.State.TERMINATED) {
            System.out.printf("Main: %s:%s , %s:%s\n", thread1.getName(), thread1.getState(), thread2.getName(), thread2.getState());
            Thread.sleep(1000);
        }
    }
}

查看控制檯日誌:對象

Main: Thread-0:NEW , Thread-1:NEW
Thread-0:開始執行,準備鎖定object。
Thread-0:成功鎖定object,執行同步模塊。
Main: Thread-0:TIMED_WAITING , Thread-1:RUNNABLE
Thread-1:開始執行,準備鎖定object。
Main: Thread-0:TIMED_WAITING , Thread-1:BLOCKED
Main: Thread-0:TIMED_WAITING , Thread-1:BLOCKED
Thread-0:被掛起,等待其餘線程喚醒本身。
Thread-1:成功鎖定object,執行同步模塊。
Main: Thread-0:WAITING , Thread-1:TIMED_WAITING
Main: Thread-0:WAITING , Thread-1:TIMED_WAITING
Main: Thread-0:WAITING , Thread-1:TIMED_WAITING
Thread-1: 喚醒其餘線程。Main: Thread-0:BLOCKED , Thread-1:TIMED_WAITING
Main: Thread-0:BLOCKED , Thread-1:TIMED_WAITING
Main: Thread-0:BLOCKED , Thread-1:TIMED_WAITING
Thread-1: 執行結束。Thread-0: 被喚起,繼續開始執行。Thread-0: 執行結束。

執行過程分析:內存

1. Thread-0與Thread-1建立之初。hadoop

  • Thread-0:NEW
  • Thread-1:NEW

2. Thread-0先啓動,獲取鎖後進入同步方法快並調用sleep方法等待3秒。Thread-1接着啓動,也嘗試獲取鎖,可是鎖已經被Thread-0獲取,Thread-1等待鎖釋放。

  • Thread-0:NEW->RUNNABLE->TIMED_WAITNG
  • Thread-1:NEW->RUNNABLE->BLOCKED

3. Thread-0等待3秒後繼續執行而後調用wait方法掛起,並釋放鎖。Thread-1獲取到鎖後開始執行同步快並等待三秒。

  • Thread-0:TIME_WAITING->RUNNABLE->WAITING
  • Thread-1:BLOCKED->RUNNABLE->TIMED_WAITING

4. Thread-1休眠3秒後喚醒Thread-0,但這個時候鎖依然被Thread-1所擁有,而後Thread-1繼續休眠3秒。Thread-0等待Thread-1釋放鎖。

  • Thread-0:WAITING->BLOCKED
  • Thread-1:TIMED_WAITING->RUNNABLE->TIMED_WAITING

5. Thread-1休眠結束後恢復,並執行完畢同步方法快後結束。Thread-0獲取鎖後恢復,執行完同步方法快後結束。

  • Thread-0:BLOCKED->RUNNABLE->TERMINATED
  • Thread-1:TIMED_WAITING->RUNNABLE->TERNINATED
相關文章
相關標籤/搜索