這篇博客介紹線程的生命週期。性能優化
線程是一個動態執行的過程,它也有從建立到死亡的過程。網絡
在 Thread 類中,有一個枚舉內部類:多線程
上面的信息以圖片表示以下:架構
第一張圖:併發
第二張圖:把等待、計時等待、阻塞當作阻塞一個狀態了分佈式
新建狀態下,線程尚未調用 start()方法啓動,只是存在一個線程對象而已ide
Thread t = new Thread();//這就是t線程的新建狀態微服務
就緒狀態:線程對象調用了 start() 方法,等待 JVM 的調度,(此時該線程並無運行)高併發
運行狀態:線程對象得到 JVM 調度,若是存在多個 CPU,那麼運行多個線程並行運行源碼分析
注意:線程對象只能調用一次 start() 方法,不然報錯:illegaThreadStateExecptiong
注意:阻塞狀態只能先進入就緒狀態,不能直接進入運行狀態
阻塞狀態分爲兩種狀況:
①、當線程 A 處於可運行狀態中,試圖獲取同步鎖時,卻被 B 線程獲取,此時 JVM 把當前 A 線程放入鎖池中,A線程進入阻塞狀態
②、當線程處於運行狀態時,發出了 IO 請求,此時進入阻塞狀態
①、當線程處於運行狀態時,調用了 wait() 方法,此時 JVM 把該線程放入等待池中
①、當線程處於運行狀態時,調用了帶參數 wait 方法,此時 JVM 把該線程放入等待池中
②、當前線程調用了 sleep(long time) 方法
①、正常終止,執行完 run() 方法,正常結束
②、強制終止,如調用 stop() 方法或 destory() 方法
③、異常終止,執行過程當中發生異常
線程休眠:讓執行的線程暫停一段時間,進入計時等待狀態。
static void sleep(long millis):調用此方法後,當前線程放棄 CPU 資源,在指定的時間內,sleep 所在的線程不會得到可運行的機會,此狀態下的線程不會釋放同步鎖。
該方法更多的是用來模擬網絡延遲,讓多線程併發訪問同一資源時的錯誤效果更加明顯。
線程等待:一旦一個線程執行到wait(),就釋放當前的鎖。
注意:此方法必須在同步代碼塊或同步方法中
喚醒:喚醒wait的一個或全部的線程
注意:此方法需和wait()成對使用,必須在同步代碼塊或同步方法中
注意 sleep() 和 wait() 的區別,sleep指定時間內當前線程放棄 CPU 資源,線程不會釋放同步鎖,wait 會放棄 CPU 資源,同時也會放棄 同步鎖
聯合線程:表示這個線程等待另外一個線程完成後(死亡)才執行,join 方法被調用以後,線程對象處於阻塞狀態。寫在哪一個線程中,哪一個線程阻塞
這種也稱爲聯合線程,就是說把當前線程和當前線程所在的線程聯合成一個線程
禮讓線程:表示當前線程對象提示調度器本身願意讓出 CPU 資源。
調用該方法後,線程對象進入就緒狀態,因此徹底有可能:某個線程調用了 yield() 方法,可是線程調度器又把它調度出來從新執行。
public class TestThread1 { public static void main(String [] args){ SubThread1 subThread1=new SubThread1(); subThread1.start(); for (int i=0;i<=100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); if(i==20){ try { subThread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } class SubThread1 extends Thread{ @Override public void run(){ for (int i=0;i<=100;i++){ try { Thread.currentThread().sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+i); } } }
運行結果:
main:0 main:1 main:2 main:3 main:4 main:5 main:6 main:7 main:8 main:9 main:10 Thread-0:0 Thread-0:1 Thread-0:2 Thread-0:3 Thread-0:4 Thread-0:5 Thread-0:6 Thread-0:7 Thread-0:8 Thread-0:9 Thread-0:10 . . . Thread-0:99 Thread-0:100 main:11 main:12 main:13 main:14 main:15 . . main:98 main:99 main:100
運行結果分析:在main線程中調用線程A的join()方法,此時main線程中止執行,直至A線程執行完畢,main線程再接着join()以後的代碼執行
/** * @author: ChenHao * @Description:使用兩個線程打印1-100,線程1,線程2交替打印 * 線程通訊:以下的三個關鍵字使用的話,都得在同步代碼塊或同步方法中。 * wait():一旦一個線程執行到wait(),就釋放當前的鎖。 * notify()/notifyAll():喚醒wait的一個或全部的線程 * 若是不使用break,程序將不會中止 * @Date: Created in 10:50 2018/10/29 */ public class TestPrintNum { public static void main(String [] args){ PrintNum printNum=new PrintNum(); Thread thread1=new Thread(printNum); Thread thread2=new Thread(printNum); thread1.start(); thread2.start(); } } class PrintNum implements Runnable{ int num=1; @Override public void run(){ while (true){ synchronized (this){ notify(); if(num<=100){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+num++); }else { break; } try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
Thread-0:1 Thread-1:2 Thread-0:3 Thread-1:4 Thread-0:5 Thread-1:6 Thread-0:7 Thread-1:8 Thread-0:9 Thread-1:10 . . .
運行結果分析:當第一個線程獲取鎖以後,打印後wait,釋放鎖;第二個線程獲取鎖,並喚醒第一個線程,打印後wait;交替打印