Java多線程之線程狀態詳解

 線程狀態

五個狀態新生就緒運行死亡阻塞

在這裡插入圖片描述

在這裡插入圖片描述

停止線程

  • 不推薦使用JDK提供的stop()、destroy()方法【已棄用】
  • 推薦線程自己停止
  • 建議用一個標志位進行終止變量,到flag=false,則終止線程運行
public class StopDemo implements Runnable {
    // 設置一個標志位
    boolean flag = true;

    @Override
    public void run() {
        // 線程體使用該標志
        while (flag) {
            System.out.println("runing....");
        }
    }

    // 設置一個公共的方法停止線程,轉換標志位
    public void stop() {
        this.flag = false;
    }
}

線程休眠

  • sleep(時間)指定當前線程阻塞的毫秒數
  • sleep存在異常 Interrupted Exception
  • sleep時間達到後線程進入就緒狀態
  • sleep可以模擬網絡延時,倒計時等
  • 每一個對象都有一個鎖,sleep不會釋放鎖(重點記下) 

模擬網絡延遲(放大問題的發生性)

搶票:

public class SleepDemo implements Runnable {
    // 票數
    private int tickeNum = 10;

    @Override
    public void run() {
        while (true) {
            if (tickeNum <= 0) {
                break;
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(String.format("%s --> 拿到瞭第%d張票", Thread.currentThread().getName(), tickeNum--));
        }
    }

    public static void main(String[] args) {
        SleepDemo sleepDemo = new SleepDemo();

        new Thread(sleepDemo, "張三").start();
        new Thread(sleepDemo, "李四").start();
        new Thread(sleepDemo, "王五").start();
    }
}

從輸出結果看,第4張票被多個人搶到瞭,產生瞭線程安全問題

在這裡插入圖片描述

模擬計時

public class SleepDemo2 {
    // 模擬倒計時
    public static void countDown() {
        int num = 5;
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
            num--;
            if (num==0) {
                break;
            }
        }
    }

    public static void main(String[] args) {
        countDown();
    }
}

在這裡插入圖片描述

線程禮讓

  • 禮讓線程,讓當前正在執行的線程暫停,但不阻塞
  • 將線程從運行狀態轉為就緒狀態
  • 讓CPU重新調度,禮讓不一定成功!看CPU心情
public class YieldDemo {
    public static void main(String[] args) {
        MyYeild myYeild = new MyYeild();
        new Thread(myYeild, "a").start();
        new Thread(myYeild, "b").start();
    }
}

class MyYeild implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 線程開始");
        // 禮讓
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + " 線程停止");
    }
}

如果a線程禮讓成功瞭,就會讓b線程先跑

在這裡插入圖片描述

插隊(線程強制執行)

  • Join合並線程,待此線程執行完成後,再執行其他線程,其他線程阻塞
  • 可以想象成食堂插隊打飯。會讓線程阻塞,慎用。
public class JoinDemo implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("vip來瞭" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        JoinDemo joinDemo = new JoinDemo();
        Thread thread = new Thread(joinDemo);
        thread.start();

        // 主線程
        for (int i = 0; i < 500; i++) {
            if (i == 200) {
                // 插隊
                thread.join();
            }
            System.out.println("main" + i);
        }
    }
}

在主線程中的i=100的時候,vip線程進來插隊,直到vip執行完,主線程才繼續

在這裡插入圖片描述

線程狀態觀測

通過一個枚舉常量:Thread.State

在這裡插入圖片描述

public class StateDemo {
    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("===========");
            }
        });

        // 觀察狀態  new
        System.out.println(thread.getState());
        // 啟動後   run
        thread.start();
        System.out.println(thread.getState());
        // 隻要線程不終止,就一直輸出狀態
        while (thread.getState() != Thread.State.TERMINATED) {
            Thread.sleep(500);
            System.out.println(thread.getState());
        }
    }
}

在這裡插入圖片描述

線程優先級

  • Java提供一個線程調度器來監控程序中啟動後進入就緒狀態的所有線程,線程調度器按照優先級決定應該調度哪個線程來執行
  • 線程的優先級用數字表示,范圍從1~10
    • Thread.MIN PRIORITY = 1;
    • Thread.MAX PRIORITY = 10;
    • Thread.NORM PRIORITY = 5;
  • 使用以下方式改變或獲取優先級
    • getPriority()、setPriority(int xxx)

不一定線程優先級高的會先跑,優先級低也隻是意味著獲得調度的概率低,並不是優先級低就不會被調用瞭,主要還是取決於CPU調度,有可能會出現性能倒置。

守護線程

線程分為用戶線程和守護線程

虛擬機必須確保用戶線程執行完畢

虛擬機不用等待守護線程執行完畢

如,後臺記錄操作日志,監控內存,垃圾回收,一些等待機制等等

總結

本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!

推薦閱讀: