在平常開發過程當中,若是咱們須要執行一些比較耗時的程序的話,通常來講都是開啓一個新線程,把耗時的代碼放在線程裏,而後開啓線程執行。但線程是會耗費系統資源的,若是有多個線程同時運行,互相之間搶佔系統資源,那無疑會對系統形成極大的壓力。因此,怎麼操做線程,保證不影響整個應用功能是很重要的,而這就須要咱們瞭解線程的生命週期了。架構
線程的生命週期有6種狀態,分別是 NEW(新建)、RUNNABLE(可運行)、BLOCKED(被阻塞)、 WAITING(等待)、TIMED_WAITING(計時等待)、TERMINATED(被終止) ,在 Thread 源碼的 State 枚舉中都有定義:併發
public static enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; private State() { } }
一、 NEW 狀態表示剛剛建立的線程,此時的線程還沒運行,也就是還沒執行start() 方法,建立線程的方式也比較簡單,能夠參考《Java併發知識:Java建立線程的三種方式》。ide
二、當線程執行時,處於 RUNNABLE 狀態,表示線程所需的資源已經準備好了。工具
三、若是線程在執行的過程當中遇到被阻塞的狀況,例如線程中的程序中有synchronized 同步代碼塊,線程就會暫停執行,進入阻塞狀態,直至獲取請求的鎖,這時線程就處於 BLOCKED 狀態。學習
實例代碼以下:this
public class ThreadDemo { public static Object testObject = new Object(); public static class MyThread extends Thread { public MyThread(String name) { super.setName(name); } @Override public void run() { //每次跑run方法都須要獲取testObject對象 synchronized (testObject) { System.out.println("thread name:" + this.getName()); //..............耗時操做.............. } } } public static void main(String[] args) { for (int i = 1; i <= 100; i++) { new MyThread("線程"+i).start(); } } }
在上面的代碼中,線程的run方法在執行耗時的程序以前都須要先獲取testobject對象的鎖,由於對象鎖是公共對象,因此,多個線程同時運行時,同一時刻只能有一個線程獲取鎖,假設某個時刻是 A線程 獲取了鎖,其餘線程就會處於等待鎖釋放的阻塞狀態,直到獲取鎖才能繼續執行程序,這就是線程的 BLOCKED 狀態。spa
四、 WAITING 表示等待的狀態,處於 WAITING 狀態的線程會進入一個 無時間限制 的等待,一旦等到了指望的事件,線程就會再次執行,進入 RUNNABLE 狀態。最典型的場景就是 等待(wait) 和 通知(notify) 。線程
等待狀態對應的方法是wait(),而通知是notify(),這兩個方法並不屬於Thread類,而是屬於Object類,因此全部對象均可以使用這兩個方法。當一個對象實例 obj 調用 wait() 方法後,當前線程就會在這個對象上等待,直到其餘線程調用 obj.notify() 爲止。這時的對象實例 obj 就至關於多個線程之間的通訊工具。實例代碼以下:3d
public class ThreadDemo { public static Object testObject = new Object(); public static class MyThread1 extends Thread { @Override public void run() { synchronized (testObject) { System.out.println("MyThread1 wait :" + System.currentTimeMillis()); try { //調用wait方法進入等待狀態 testObject.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static class MyThread2 extends Thread { @Override public void run() { synchronized (testObject) { System.out.println("MyThread2 start notify :" + System.currentTimeMillis()); //..............耗時操做.............. //發出通知,喚醒等待的線程 testObject.notify(); } } } public static void main(String[] args) { MyThread1 t1 = new MyThread1(); MyThread2 t2 = new MyThread2(); t1.start(); t2.start(); } }
五、 TIMED_WAITING 和 WAITING 同樣,都表示等待狀態,但TIMED_WAITING 會進行一個 有時限的等待 。操做線程狀態有幾個方法是帶有超時參數的,調用方法的線程進入計時等待狀態。這一狀態將一直保持到超時期滿或者接收到適當的通知,最多見的應用就是調用 Thread.sleep() 方法。視頻
實例代碼以下:
public static class MyThread extends Thread { @Override public void run() { System.out.println("MyThread start :" + System.currentTimeMillis()); try { //休眠兩秒鐘 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("MyThread end :" + System.currentTimeMillis()); } } public static void main(String[] args) { MyThread t = new MyThread1(); t.start(); }
啓動線程後,程序運行到 Thread.sleep() 方法會處於休眠狀態,時間根據參數來決定,單位是毫秒,因此執行main方法後,後一條輸出內容會隔兩秒鐘出現。在此我向你們推薦一個架構學習交流裙。交流學習裙號:681179158,裏面會分享一些資深架構師錄製的視頻錄像
MyThread start :1544704974271 MyThread end :1544704976272
六、當線程執行完畢後,進入 TERMINATED 狀態,表示結束,通常線程被終止有兩種緣由:
run方法正常運行後就天然消亡。
由於一個沒有捕獲的異常終止了run方法而致使意外死亡。
好了,線程的生命週期就總結完了,用一張圖表示大概是這樣: