您好,登錄后才能下訂單哦!
這篇文章給大家介紹Java中線程順序執行解析,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
調用Thread的start()方法啟動線程時,線程的執行順序是不確定的。也就是說,在同一個方法中,連續創建多個線程后,調用線程的start()方法的順序并不能決定線程的執行順序。
例如,這里,看一個簡單的示例程序,如下所示。
package io.binghe.concurrent.lab03; /** * @author binghe * @version 1.0.0 * @description 線程的順序,直接調用Thread.start()方法執行不能確保線程的執行順序 */ public class ThreadSort01 { public static void main(String[] args){ Thread thread1 = new Thread(() -> { System.out.println("thread1"); }); Thread thread2 = new Thread(() -> { System.out.println("thread2"); }); Thread thread3 = new Thread(() -> { System.out.println("thread3"); }); thread1.start(); thread2.start(); thread3.start(); } }
在ThreadSort01類中分別創建了三個不同的線程,thread1、thread2和thread3,接下來,在程序中按照順序分別調用thread1.start()、thread2.start()和thread3.start()方法來分別啟動三個不同的線程。
那么,問題來了,線程的執行順序是否按照thread1、thread2和thread3的順序執行呢?運行ThreadSort01的main方法,結果如下所示。
thread1 thread2 thread3
再次運行時,結果如下所示。
thread1 thread3 thread2
第三次運行時,結果如下所示。
thread2 thread3 thread1
注意:每個人運行的情況可能都不一樣。
可以看到,每次運行程序時,線程的執行順序可能不同。線程的啟動順序并不能決定線程的執行順序。
在實際業務場景中,有時,后啟動的線程可能需要依賴先啟動的線程執行完成才能正確的執行線程中的業務邏輯。此時,就需要確保線程的執行順序。那么如何確保線程的執行順序呢?
可以使用Thread類中的join()方法來確保線程的執行順序。例如,下面的測試代碼。
package io.binghe.concurrent.lab03; /** * @author binghe * @version 1.0.0 * @description 線程的順序,Thread.join()方法能夠確保線程的執行順序 */ public class ThreadSort02 { public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(() -> { System.out.println("thread1"); }); Thread thread2 = new Thread(() -> { System.out.println("thread2"); }); Thread thread3 = new Thread(() -> { System.out.println("thread3"); }); thread1.start(); //實際上讓主線程等待子線程執行完成 thread1.join(); thread2.start(); thread2.join(); thread3.start(); thread3.join(); } }
可以看到,ThreadSort02類比ThreadSort01類,在每個線程的啟動方法下面添加了調用線程的join()方法。此時,運行ThreadSort02類,結果如下所示。
thread1 thread2 thread3
再次運行時,結果如下所示。
thread1 thread2 thread3
第三次運行時,結果如下所示。
thread1 thread2 thread3
可以看到,每次運行的結果都是相同的,所以,使用Thread的join()方法能夠保證線程的先后執行順序。
既然Thread類的join()方法能夠確保線程的執行順序,我們就一起來看看Thread類的join()方法到底是個什么鬼。
進入Thread的join()方法,如下所示。
public final void join() throws InterruptedException { join(0); }
可以看到join()方法調用同類中的一個有參join()方法,并傳遞參數0。繼續跟進代碼,如下所示。
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
可以看到,有一個long類型參數的join()方法使用了synchroinzed修飾,說明這個方法同一時刻只能被一個實例或者方法調用。由于,傳遞的參數為0,所以,程序會進入如下代碼邏輯。
if (millis == 0) { while (isAlive()) { wait(0); } }
首先,在代碼中以while循環的方式來判斷當前線程是否已經啟動處于活躍狀態,如果已經啟動處于活躍狀態,則調用同類中的wait()方法,并傳遞參數0。繼續跟進wait()方法,如下所示。
public final native void wait(long timeout) throws InterruptedException;
可以看到,wait()方法是一個本地方法,通過JNI的方式調用JDK底層的方法來使線程等待執行完成。
需要注意的是,調用線程的wait()方法時,會使主線程處于等待狀態,等待子線程執行完成后再次向下執行。也就是說,在ThreadSort02類的main()方法中,調用子線程的join()方法,會阻塞main()方法的執行,當子線程執行完成后,main()方法會繼續向下執行,啟動第二個子線程,并執行子線程的業務邏輯,以此類推。
關于Java中線程順序執行解析就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。