1. 程式人生 > 其它 >Java多執行緒:執行緒狀態

Java多執行緒:執行緒狀態

執行緒狀態

  • 建立狀態
  • 就緒狀態
  • 執行狀態
  • 阻塞狀態
  • 死亡狀態,一旦結束無法再啟動

執行緒方法

執行緒停止

  • 不推薦使用JDK提供的stop()destory()方法停止執行緒,推薦執行緒自己停止下來
  • 建議使用一個標誌位進行中止變數,當flag = false,中止執行緒執行
  • 建議執行緒正常停止,利用次數,不進行死迴圈
public class TestStop implements Runnable{
    //設定標誌位
    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while (flag){
            System.out.println("run" + i++);
        }
    }

    //設定公開方法停止執行緒,轉換標誌位
    public void stop(){
        this.flag = false;
    }

    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        new Thread(testStop).start();

        for (int i = 0; i < 200; i++) {
            System.out.println("main" + i);//計時
            if (i == 99){
                testStop.stop();
                System.out.println("stop");
                break;
            }
        }
    }
}

執行緒休眠sleep

  • sleep(時長):指定當前執行緒阻塞的毫秒數
  • sleep存在異常InterruptedException
  • sleep時間達到後執行緒進入就緒狀態
  • sleep可以模擬網路延時,倒計時等(放大問題的發生性)
  • 每一個物件都有一個鎖,sleep不會釋放鎖

倒計時

public static void tenDown() throws InterruptedException {
    int num = 10;
    while (true){
        System.out.println(num--);
        Thread.sleep(1000);
        if (num < 0){
            break;
        }
    }
}

顯示當前時間

public static void main(String[] args) {
    //列印當前時間
    Date startTime = new Date(System.currentTimeMillis());

    while(true){
        try {
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
            Thread.sleep(1000);
            startTime = new Date(System.currentTimeMillis());//重新整理時間
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

執行緒禮讓yield

  • 讓當前正在執行的執行緒暫停,但不阻塞
  • 令執行緒從執行狀態轉變為就緒狀態
  • 令CPU重新排程,但不一定成功
public class TestYield {
    public static void main(String[] args) {
        MyYield myYield1 = new MyYield();
        MyYield myYield2 = new MyYield();

        new Thread(myYield1,"a").start();
        new Thread(myYield2,"b").start();
    }
}

class MyYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ",start");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + ",over");
    }
}

執行緒強制執行join

  • join合併執行緒,此執行緒執行完再執行其他執行緒,其他執行緒阻塞
  • 類似於插隊,霸佔所有資源完成任務
public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 77; i++) {
            System.out.println("插隊,霸佔所有資源" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //啟動執行緒
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();

        //主執行緒
        for (int i = 0; i < 1000; i++) {
            //在200以前是CPU排程多執行緒執行,20後是join執行,霸佔資源
            if (i == 20){
                thread.join();
            }
            System.out.println("main:" + i);
        }
    }
}

執行緒狀態觀測

Thread.State,狀態為以下之一:

  • NEW:暫未啟動的執行緒
  • RUNNABLE:在執行的執行緒
  • BLOCKED:被阻塞等到監視器鎖定的執行緒
  • WAITING:在等待另一個執行緒執行特定動作的執行緒
  • TIMED_WAITING:在等待另一個執行緒執行動作達到指定等待時間的執行緒
  • TERMINATED:已退出的執行緒
//觀察測試執行緒的狀態
public class TestState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("==========");//輸出後執行緒中止
        });

        //觀察狀態
        Thread.State state = thread.getState();
        System.out.println(state);

        //啟動後狀態
        thread.start();
        state = thread.getState();
        System.out.println(state);

        while (state != Thread.State.TERMINATED){
            Thread.sleep(100);
            state = thread.getState();//更新狀態
            System.out.println(state);
        }
        
        //執行緒停止後無法再啟動
    }
}

執行緒優先順序

  • Java提供一個執行緒排程器監控程式中啟動後進入就緒狀態的所有執行緒,執行緒排程器按照優先順序決定排程執行緒

  • 優先順序由數字表示,範圍為1-10:

    • Thread.MIN_PRIORITY = 1;
    • Thread.Max_PRIORITY = 10;
    • Thread.NORM_PRIORITY = 5;預設優先順序
  • getPriority():獲取優先順序

  • setPriority(int num):改變優先順序

先設定優先順序再執行,設定了優先順序排程還是由CPU決定

public class TestPriority {
    public static void main(String[] args) {
        //主執行緒預設優先順序
        System.out.println(Thread.currentThread().getName() + "的優先順序為:" + Thread.currentThread().getPriority());

        MyPriority myPriority = new MyPriority();
        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        Thread t5 = new Thread(myPriority);

        //設定優先順序,啟動
        t1.start();

        t2.setPriority(1);
        t2.start();

        t3.setPriority(4);
        t3.start();

        t4.setPriority(Thread.MAX_PRIORITY);//最大
        t4.start();

        t5.setPriority(5);
        t5.start();


    }
}

class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "的優先順序為:" + Thread.currentThread().getPriority());
    }
}

輸出結果

main的優先順序為:5
Thread-0的優先順序為:5
Thread-3的優先順序為:10
Thread-4的優先順序為:5
Thread-2的優先順序為:4
Thread-1的優先順序為:1

守護(daemon)執行緒

  • 執行緒分為使用者執行緒守護執行緒
  • 虛擬機器必須確保使用者執行緒執行完畢
  • 虛擬機器不必等待守護執行緒執行完畢
  • 如:後臺記錄,回收
  • setDaemon(true):設定為守護執行緒;預設為false,表示使用者執行緒,一般執行緒都是使用者執行緒

程式在執行完使用者執行緒後結束,不需要等待守護執行緒執行結束

public class TestDaemon {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();

        Thread thread = new Thread(god);
        thread.setDaemon(true); //預設為false,表示使用者執行緒,一般執行緒都是使用者執行緒

        thread.start(); //啟動守護執行緒
        new Thread(you).start(); //啟動使用者執行緒
    }
}


//God,守護執行緒
class God implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("see");
        }
    }
}

//你,使用者執行緒
class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            System.out.println("活");
        }
        System.out.println("=====結束了=====");
    }
}