新建狀態(New):當線程對象對建立後,即進入了新建狀態,如:Thread t = new MyThread();html
就緒狀態(Runnable):當調用線程對象的start()方法(t.start();),線程即進入就緒狀態。處於就緒狀態的線程,只是說明此線程已經作好了準備,隨時等待CPU調度執行,並非說執行了t.start()此線程當即就會執行;java
運行狀態(Running):當CPU開始調度處於就緒狀態的線程時,此時線程才得以真正執行,即進入到運行狀態。注:就 緒狀態是進入到運行狀態的惟一入口,也就是說,線程要想進入運行狀態執行,首先必須處於就緒狀態中;ide
阻塞狀態(Blocked):處於運行狀態中的線程因爲某種緣由,暫時放棄對CPU的使用權,中止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被CPU調用以進入到運行狀態。根據阻塞產生的緣由不一樣,阻塞狀態又能夠分爲三種:函數
1.等待阻塞:運行狀態中的線程執行wait()方法,使本線程進入到等待阻塞狀態;this
2.同步阻塞 -- 線程在獲取synchronized同步鎖失敗(由於鎖被其它線程所佔用),它會進入同步阻塞狀態;spa
3.其餘阻塞 -- 經過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程從新轉入就緒狀態。線程
死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命週期。3d
public class MyThread extends Thread { @Override public void run() { System.out.println("MyThread:run"); } public static void main(String[] args) { Thread thread = new MyThread(); thread.start(); } }
public class MyRunnable implements Runnable { @Override public void run() { System.out.println("MyRunnable:run"); } public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); } }
public class MyCallable implements Callable<String> { @Override public String call() { try { System.out.println("MyCallable:run"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return "MyCallable:call"; } public static void main(String[] args) { MyCallable myCallable = new MyCallable(); FutureTask<String> task = new FutureTask<String>(myCallable); Thread thread = new Thread(task); thread.start(); try { System.out.println(task.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
task.get()的時候阻塞,直到會調用task的線程執行完返回後才繼續code
sleep:線程暫停執行,但不會釋放「鎖標誌」,使用CPU能夠調度其它線程htm
yield:只是使當前線程從新回到可執行狀態,因此執行yield()的線程有可能在進入到可執行狀態後立刻又被執行
wait:在synchronized包括的塊中使用wait,線程暫停執行,會釋放synchronized的「鎖標誌」,直到notify()或notifyAll()後纔會喚醒
join:等待調用的線程執行完後,在繼續執行當前線程
使用sleep和yield例子:
public class MyRunnable implements Runnable { @Override public void run() { Thread.yield(); try { Thread.sleep(3000); //暫停毫秒爲單位,能夠經過interrupt拋出異常 System.out.println(Thread.currentThread()); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { new Thread(new MyRunnable()).start(); } }
wait使用:
public class MyRunnable implements Runnable { private Object value; public MyRunnable(Object value) { this.value = value; } @Override public void run() { synchronized (value) { try { System.out.println("執行wait"); value.wait(); System.out.println(Thread.currentThread()); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Object lock = new Object(); new Thread(new MyRunnable(lock)).start(); try { Thread.sleep(2000); synchronized (lock) { System.out.println("執行notify"); lock.notify(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
執行結果:
能夠發現是當線程調用wait後,是主線程調用了notify後,線程才繼續執行
join例子:
public class MyRunnable implements Runnable { @Override public void run() { try { System.out.println("執行sleep"); Thread.sleep(5000); System.out.println(Thread.currentThread()); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); try { thread.join(); System.out.println("執行join後"); } catch (InterruptedException e) { e.printStackTrace(); } } }
執行結果
這個方法只會給線程設置一個爲true的中斷標誌(中斷標誌只是一個布爾類型的變量),而設置以後,則根據線程當前的狀態進行不一樣的後續操做。
1. 若是線程的當前狀態處於非阻塞狀態,那麼僅僅是線程的中斷標誌被修改成true而已;
2. 若是線程的當前狀態處於阻塞狀態,那麼在將中斷標誌設置爲true後,還會有以下三種狀況之一的操做:
(1) 若是是wait、sleep以及jion三個方法引發的阻塞,那麼會將線程的中斷標誌從新設置爲false,並拋出一個InterruptedException;
(2) 若是是java.nio.channels.InterruptibleChannel進行的io操做引發的阻塞,則會對線程拋出一個ClosedByInterruptedException;(待驗證)
(3) 若是是輪詢(java.nio.channels.Selectors)引發的線程阻塞,則當即返回,不會拋出異常。(待驗證)
若是在中斷時,線程正處於非阻塞狀態,則將中斷標誌修改成true,而在此基礎上,一旦進入阻塞狀態,則按照阻塞狀態的狀況來進行處理;例如,一個線程在運行狀態中,其中斷標誌被設置爲true,則此後,一旦線程調用了wait、jion、sleep方法中的一種,立馬拋出一個InterruptedException,且中斷標誌被清除,從新設置爲false。
經過上面的分析,咱們能夠總結,調用線程類的interrupted方法,其本質只是設置該線程的中斷標誌,將中斷標誌設置爲true,並根據線程狀態決定是否拋出異常。所以,經過interrupted方法真正實現線程的中斷原理是:開發人員根據中斷標誌的具體值,來決定如何退出線程。
參考:http://www.javashuo.com/article/p-kpmzihkf-ck.html
public class MyRunnable implements Runnable { @Override public void run() { try { System.out.println("執行sleep"); Thread.sleep(5000); //當在暫停中調用interrupt,就拋出了異常InterruptedException System.out.println(Thread.currentThread()); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); thread.interrupt(); } }
執行結果:
線程默認false是用戶線程,經過setDaemon(true)設置線程爲守護線程
只能在start以前設置,否則會報IllegalThreadStateException異常
用戶線程和守護線程的區別:
1.主線程結束後用戶線程還會繼續運行
2.若是沒有用戶線程,都是守護線程,那麼JVM結束。
例子:
public class MyRunnable implements Runnable { @Override public void run() { try { System.out.println("執行sleep"); Thread.sleep(5000); //當在暫停中調用interrupt,就拋出了異常InterruptedException System.out.println(Thread.currentThread()); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.setDaemon(true); thread.start(); try { Thread.sleep(2000); System.out.println("結束程序"); } catch (InterruptedException e) { e.printStackTrace(); } } }
結果:
能夠看到沒有等線程thread執行完,程序就結束了