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的更多內容!