咱們知道在Java裏線程是經過java.lang.Thread
類來實現的。通常咱們建立無返回值的線程會用下面兩個方法:java
線程啓動會經過調用start方法來啓動線程而不能直接調用run方法。面試
這裏就會引出兩個經典的面試題:markdown
- 爲何線程啓動是調用start方法來啓動線程而不能直接調用run方法?
- 若是屢次調用start方法會發生什麼?
其實答案就是源碼裏,在這以前咱們要了解線程的狀態有哪些。多線程
線程從建立到死亡是會經歷多個狀態的流轉的。它們分別是:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
。ide
// Thread類的內部的枚舉類定義了線程的狀態 public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; } 複製代碼
從上圖中,咱們就能夠看到,在New了一個線程後,首先進入初始態,而後調用start()方法來到就緒態,這裏並不會當即執行線程裏的任務,而是會等待系統資源分配,當分配到時間片後就能夠開始運行了。 start()方法是一個native方法,它將啓動一個新線程,並執行run()方法,這是真正的多線程工做。 而直接執行 run() 方法,會把 run 方法當成一個 main 線程下的普通方法去執行,並不會在某個線程中執行它,因此這並非多線程工做。這就是爲何調用 start() 方法時會執行 run() 方法,爲何不能直接調用 run() 方法的緣由了。oop
Example:測試
public class ThreadDemo public static void main(String[] args) { Thread t1 = new Thread(new Task1()); Thread t2 = new Thread(new Task2()); // 測試1 t1.start(); t2.start(); // 測試2 t1.run(); t2.run(); } } class Task1 implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("Task1: " + i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Task2 implements Runnable { @Override public void run() { for (int i = 10; i > 0; i--) { System.out.println("Task2: " + i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } // 測試1輸出 Task1: 0 Task2: 10 Task1: 1 Task2: 9 Task1: 2 Task2: 8 Task1: 3 Task2: 7 Task1: 4 Task2: 6 Task1: 5 Task2: 5 Task1: 6 Task2: 4 Task1: 7 Task2: 3 Task1: 8 Task2: 2 Task1: 9 Task2: 1 咱們能夠看到Task1 和 Task2是交替打印的,是多線程在運行。 // 測試2輸出 Task1: 0 Task1: 1 Task1: 2 Task1: 3 Task1: 4 Task1: 5 Task1: 6 Task1: 7 Task1: 8 Task1: 9 Task2: 10 Task2: 9 Task2: 8 Task2: 7 Task2: 6 Task2: 5 Task2: 4 Task2: 3 Task2: 2 Task2: 1 這個的輸出是串行的,Task1 執行完才執行 Task2,因此不是多線程,是普通方法。 複製代碼
首先咱們先測試一下。this
Example:spa
public class ThreadDemo public static void main(String[] args) { Thread t1 = new Thread(new Task1()); Thread t2 = new Thread(new Task2()); // 測試3 t1.start(); t1.start(); } } // 測試3輸出 Task1: 0 Task... Exception in thread "main" java.lang.IllegalThreadStateException at java.lang.Thread.start(Thread.java:708) Task... 複製代碼
只有第一次成功執行,後面就拋出了異常java.lang.IllegalThreadStateException
,讓咱們來從下面的源碼裏看看吧,在start方法進來後就會判斷線程的狀態,若是不是初始態狀態就會拋出異常,因此第二次執行就會報錯,由於線程的狀態已經發生改變。線程
start()方法源碼:
public synchronized void start() { // 若是線程不是"NEW狀態",則拋出異常! if (threadStatus != 0) throw new IllegalThreadStateException(); // 將線程添加到ThreadGroup中 group.add(this); boolean started = false; try { // 經過start0()啓動線程,新線程會調用run()方法 start0(); // 設置started標記=true started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } } 複製代碼
run方法源碼:
public void run() { if (target != null) { target.run(); } } 複製代碼
start()方法是用來啓動線程,真正實現了多線程運行。
run()方法是一個普通方法。
調用start()方法後會先判斷線程的狀態是否爲NEW,因此線程只能啓動一次。
本文使用 mdnice 排版