本文描述Java線程線程狀態及狀態轉換,不會涉及過多理論,主要以代碼示例說明線程狀態如何轉換。java
線程能夠有6種狀態:多線程
new Thread()
後線程的狀態就是新建。start()
方法,不管是否運行,狀態都爲Runable,注意Runable狀態指示表示線程能夠運行,不表示線程當下必定在運行,線程是否運行由虛擬機所在操做系統調度決定。Monitor
(進入synchronized
方法或synchronized
塊)可是其餘線程已經搶先獲取,那此線程被阻塞,知道其餘線程釋放Monitor
而且線程調度器容許當前線程獲取到Monitor
,此線程就恢復到可運行狀態。線程從「新建」到「被終止」會歷經屢次狀態轉換,全部可能的轉換以下圖:ide
【圖一】spa
觀察狀態轉化圖,咱們發現「可運行」狀態爲全部狀態的必經狀態。咱們分析出四條基本的狀態轉換線路圖。操作系統
「新建」和「被終止」狀態分別爲起始和結束狀態,和「可運行」狀態不可逆。其餘狀態均能和「可運行」狀態相互轉換。線程
讓咱們用代碼演示線程狀態是如何轉換的,你們重點關注兩個問題?code
這個狀態轉換時建立的線程生命週期。orm
/** * NEW->RUNNABLE->TERMINATED */ public class ThreadStateNRT { public static void main(String[] args) { Thread thread=new Thread(new Task()); print(thread.getName(),thread.getState()); thread.start(); //等待線程執行完畢。 try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } print(thread.getName(),thread.getState()); } private static class Task implements Runnable{ @Override public void run() { print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } private static final String stringFormat="%s:%s"; private static void print(String threadName,Thread.State state){ System.out.println(String.format(stringFormat,threadName,state)); } }
其中,print()
方法用來打印線程信息。後面的代碼示例均不在展現。對象
運行程序結果爲:生命週期
Thread-0:NEW
Thread-0:RUNNABLE
Thread-0:TERMINATED
只有一種方法能出現阻塞狀態,那就是synchronized
同步原語。咱們須要兩個線程其中一個線程被另外一個阻塞來展現。
/** * NEW->RUNNABLE->BLOCKED->RUNNABLE->TERMINATED */ public class ThreadStateNRBRT { //鎖 private static final Object lock=new Object(); public static void main(String[] args) { //輔助線程,製造synchronized狀態。 Thread assistantThread = new Thread(new SynTask()); assistantThread.start(); try { //保證assistantThread先執行。 Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } Thread showThread = new Thread(new Task()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(),showThread.getState()); //由於沒法判斷顯示線程什麼時候執行,因此循環直到顯示線程執行。 while (true){ if(showThread.getState()==Thread.State.BLOCKED){ print(showThread.getName(), Thread.State.BLOCKED); break; } } //等待兩個線程執行完畢。 try { assistantThread.join(); showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執行完畢打印狀態。 print(showThread.getName(), showThread.getState()); } private static class SynTask implements Runnable { @Override public void run() { //鎖定必定時間 synchronized (lock){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } private static class Task implements Runnable { @Override public void run() { synchronized (lock){ print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } } }
執行一下你有可能看到正確結果:
Thread-1:NEW
Thread-1:RUNNABLE
Thread-1:BLOCKED
Thread-1:RUNNABLE
Thread-1:TERMINATED
爲何是有可能呢?咱們調整一下代碼,例如將加鎖的時間調小一點:
private static class SynTask implements Runnable { @Override public void run() { //鎖定必定時間 synchronized (lock){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }
注意此處Thread.sleep(10)
,咱們只鎖住十毫秒。
再運行一下,控制檯可能打印出這樣的結果且程序不會結束:
Thread-1:NEW
Thread-1:RUNNABLE
Thread-1:RUNNABLE
形成以上結果的緣由是我麼沒法保證兩個線程的執行順序,也沒法證主線程必定能打印出顯示線程阻塞的狀態。
while (true){ if(showThread.getState()==Thread.State.BLOCKED){ print(showThread.getName(), Thread.State.BLOCKED); break; } }
因此執行在這段代碼死循環了。
調整一下代碼,保證不會由於參數調整改變線程之間的執行順序和打印結果。
/** * NEW->RUNNABLE->BLOCKED->RUNNABLE->TERMINATED */ public class ThreadStateNRBRT_New { //鎖 private static final Object lock=new Object(); //鎖定標誌 private volatile static boolean lockFlag=true; //執行順序 private volatile static int order=0; public static void main(String[] args) { //展現線程 Thread showThread = new Thread(new Task()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(), showThread.getState()); //輔助線程,製造synchronized狀態。 Thread assistantThread = new Thread(new SynTask()); assistantThread.start(); //循環讀取展現線程狀態,直到讀到展現線程狀態爲BLOCKED,才讓輔助線程退出同步。 while (true){ if(showThread.getState()==Thread.State.BLOCKED){ print(showThread.getName(), Thread.State.BLOCKED); lockFlag=false; break; } } try { assistantThread.join(); showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執行完畢打印狀態。 print(showThread.getName(), showThread.getState()); } private static class SynTask implements Runnable { @Override public void run() { while (true) { //保證先進入同步範圍。 if (order == 0) { synchronized (lock) { //啓動另外一個同步 order=1; //等待主線程讀取到線程阻塞狀態,退出同步。 while (lockFlag) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } break; } } } } private static class Task implements Runnable { @Override public void run() { while (true){ //保證後進入同步範圍。 if (order==1){ synchronized (lock){ print(Thread.currentThread().getName(),Thread.currentThread().getState()); } break; } } } } }
咱們用order
保證線程進入同步區的順序,用lockFlag
保證只有在打印出顯示線程的被阻塞狀態後輔助線程才退出同步區。這樣不管如何執行咱們都會獲得一樣的結果。
Thread-0:NEW
Thread-0:RUNNABLE
Thread-0:BLOCKED
Thread-0:RUNNABLE
Thread-0:TERMINATED
這裏咱們展現兩種三種方法形成線程的等待狀態
其餘方法如Thread.join()
等你們能夠參考示例代碼本身實現。
/** * NEW->RUNNABLE->WAITING->RUNNABLE->TERMINATED */ public class ThreadStateNRWRT { //鎖 private static final Object lock=new Object(); public static void main(String[] args) { //展現線程 Thread showThread = new Thread(new WaitTask()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(),showThread.getState()); //循環讀取展現線程狀態,直到讀到展現線程狀態爲WAITING,才讓輔助線程喚醒等待線程。 while (true){ if(showThread.getState()==Thread.State.WAITING){ print(showThread.getName(), Thread.State.WAITING); break; } } synchronized (lock){ lock.notify(); } try { showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執行完畢打印狀態。 print(showThread.getName(), showThread.getState()); } private static class WaitTask implements Runnable { @Override public void run() { //等待 synchronized (lock){ try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } }
/** * NEW->RUNNABLE->WAITING->RUNNABLE->TERMINATED */ public class ThreadStateNRWRTLock { //鎖 private static Lock lock=new ReentrantLock(); //鎖定標誌 private volatile static boolean lockFlag=true; //執行順序 private volatile static int order=0; public static void main(String[] args) { //展現線程 Thread showThread = new Thread(new Task()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(), showThread.getState()); //輔助線程,製造synchronized狀態。 Thread assistantThread = new Thread(new SynTask()); assistantThread.start(); //循環讀取展現線程狀態,直到讀到展現線程狀態爲BLOCKED,才讓輔助線程退出同步。 while (true){ if(showThread.getState()==Thread.State.WAITING){ print(showThread.getName(), Thread.State.WAITING); lockFlag=false; break; } } try { assistantThread.join(); showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執行完畢打印狀態。 print(showThread.getName(), showThread.getState()); } private static class SynTask implements Runnable { @Override public void run() { while (true) { //保證先進入同步範圍。 if (order == 0) { //加鎖 lock.lock(); try { order=1; while (lockFlag) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }finally { lock.unlock(); } break; } } } } private static class Task implements Runnable { @Override public void run() { while (true){ //保證後進入同步範圍。 if (order==1){ lock.lock(); try{ print(Thread.currentThread().getName(),Thread.currentThread().getState()); }finally { lock.unlock(); } break; } } } } }
/** * NEW->RUNNABLE->WAITING->RUNNABLE->TERMINATED */ public class ThreadStateNRWRTCondition { //鎖 private static Lock lock=new ReentrantLock(); private static Condition condition=lock.newCondition(); public static void main(String[] args) { //展現線程 Thread showThread = new Thread(new WaitTask()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(),showThread.getState()); //循環讀取展現線程狀態,直到讀到展現線程狀態爲WAITING,才讓輔助線程喚醒等待線程。 while (true){ if(showThread.getState()==Thread.State.WAITING){ print(showThread.getName(), Thread.State.WAITING); break; } } lock.lock(); try{ condition.signal(); }finally { lock.unlock(); } try { showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執行完畢打印狀態。 print(showThread.getName(), showThread.getState()); } private static class WaitTask implements Runnable { @Override public void run() { //等待 lock.lock(); try{ try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } }finally { lock.unlock(); } print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } }
三段代碼的運行結果都是:
Thread-0:NEW
Thread-0:RUNNABLE
Thread-0:WAITING
Thread-0:RUNNABLE
Thread-0:TERMINATED
咱們展現兩個方法形成計時等待狀態
其餘方法如Thread.sleep(long millis)
,Thread.join(long millis)
等你們能夠本身實現。
感受凡有超時方法的方法都能讓線程狀態進入計時等待,可是這個沒有通過驗證,因此只是一個猜測。
/** * NEW->RUNNABLE->TIMED_WAITING->RUNNABLE->TERMINATED */ public class ThreadStateNRTWRT { //鎖 private static final Object lock=new Object(); public static void main(String[] args) { //展現線程 Thread showThread = new Thread(new WaitTask()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(),showThread.getState()); //循環讀取展現線程狀態,直到讀到展現線程狀態爲TIMED_WAITING。 while (true){ if(showThread.getState()==Thread.State.TIMED_WAITING){ print(showThread.getName(), Thread.State.TIMED_WAITING); break; } } try { showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執行完畢打印狀態。 print(showThread.getName(), showThread.getState()); } private static class WaitTask implements Runnable { @Override public void run() { //等待 synchronized (lock){ try { lock.wait(1); } catch (InterruptedException e) { e.printStackTrace(); } } print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } }
/** * NEW->RUNNABLE->TIMED_WAITING->RUNNABLE->TERMINATED */ public class ThreadStateNRTWRTCondition { //鎖 private static Lock lock=new ReentrantLock(); private static Condition condition=lock.newCondition(); public static void main(String[] args) { //展現線程 Thread showThread = new Thread(new WaitTask()); print(showThread.getName(), showThread.getState()); showThread.start(); print(showThread.getName(),showThread.getState()); //循環讀取展現線程狀態,直到讀到展現線程狀態爲TIMED_WAITING。 while (true){ if(Thread.State.TIMED_WAITING==showThread.getState()){ print(showThread.getName(), Thread.State.TIMED_WAITING); break; } } try { showThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //線程執行完畢打印狀態。 print(showThread.getName(), showThread.getState()); } private static class WaitTask implements Runnable { @Override public void run() { //等待 lock.lock(); try{ try { condition.await(1,TimeUnit.MILLISECONDS); } catch (InterruptedException e) { e.printStackTrace(); } }finally { lock.unlock(); } print(Thread.currentThread().getName(),Thread.currentThread().getState()); } } }
兩段程序的運行結果相同:
Thread-0:NEW
Thread-0:RUNNABLE
Thread-0:TIMED_WAITING
Thread-0:RUNNABLE
Thread-0:TERMINATED
至此,咱們已經介紹了線程狀態轉換的全部狀況,瞭解線程狀態轉換對分析多線程代碼運行很幫助。但願本篇文章對你們從此工做有所助力。
《Java核心技術+卷1》第九版