老鐵們好,這裏是java研究所。
作java的,junit應該很是熟悉吧,每天和這哥們打交道,沒想到這哥們卻隱藏了一個神坑,咱們一塊兒來看下。java
運行下面的main方法,會輸出什麼?面試
public class JunitTest { public static void main(String[] args) { System.out.println("main thread"); new Thread() { @Override public void run() { System.out.println("子線程 start"); try { //休眠1秒 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("子線程 end"); } }.start(); } }
很明顯會輸出ide
main thread 子線程 start 子線程 end
ok,結果確實沒問題。學習
我們來調整一下代碼,以下,將main方法中的代碼用junit來運行,而後運行test1方法,你們以爲會輸出什麼???結果會和main方法的輸出同樣麼??測試
import org.junit.Test; public class JunitTest { @Test public void test1() { System.out.println("main thread"); new Thread() { @Override public void run() { System.out.println("子線程 start"); try { //休眠1秒 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("子線程 end"); } }.start(); } }
我們來運行一下,納尼,這什麼狀況,結果爲何比main中的少了一行????
idea
我覺得idea出問題了,而後又運行了幾回,結果仍是同樣,估計少的結果被 junit 生吞了。spa
上面代碼的特色:主線程中開啓了子線程,若是代碼是在main方法中執行,程序會等到全部線程都執行完畢纔會結束;而junit會在主線程執行完畢以後,就會將程序結束。線程
我們知道能夠經過下面代碼結束程序debug
java.lang.System.exit(int status) // status=0:正常退出 ,其餘非正常退出
我估計junit會主線程執行完畢以後,會調用 System.exit 來退出程序,咱們須要來驗證一下想法,怎麼驗證呢??code
只須要在exit方法中設置一個斷點,而後從新執行程序
debug模式下,再次執行一下test1方法,果不其然,進到exit方法中了
那怎麼辦??如何讓全部線程執行完畢以後再退出
方式1:主線程中休眠一段時間
能夠預估一下測試案例會運行多久,好比10秒就夠了,那麼能夠在方法最後一行使用sleep讓線程休眠一段時間。
@Test public void test1() throws InterruptedException { System.out.println("main thread"); new Thread() { @Override public void run() { System.out.println("子線程 start"); try { //休眠1秒 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("子線程 end"); } }.start(); //讓主線程休眠10秒 Thread.sleep(10000); }
這種方式的優勢是寫起來簡單,加一行代碼就搞定了。
方式2:join的方式
@Test public void test1() throws InterruptedException { System.out.println("main thread"); Thread thread1 = new Thread() { @Override public void run() { System.out.println("子線程 start"); try { //休眠1秒 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("子線程 end"); } }; thread1.start(); //join方法會阻塞當前主線程,直到thread1線程執行完畢 thread1.join(); }
方式3:CountDownLatch
@Test public void test1() throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(1); System.out.println("main thread"); Thread thread1 = new Thread() { @Override public void run() { try { System.out.println("子線程 start"); try { //休眠1秒 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("子線程 end"); } finally { countDownLatch.countDown(); } } }; thread1.start(); //countDownLatch.await方法會阻塞當前線程,直到thread1執行完畢 countDownLatch.await(); }
更多面試題
- B站上有哪些值得推薦學習的視頻?
- 經典面試題:重寫equals方法時,爲何必須重寫hashCode方法?
- 經典面試題:HashMap的默認容量爲何是16 ?
- 經典面試題:Arraylist和Linkedlist到底有什麼區別???
- 經典面試題:NoClassDefFoundError 和 ClassNotFoundException 有什麼區別?
- 經典面試題:Throwable、Exception、Error、RuntimeException到底有什麼區別?
- 經典面試題:try、finally中都有return時,代碼如何執行????
- 面對億級數據,MySQL到底行不行,一塊兒來看看!!
- 經典面試題:ThreadLocal連環炮!!
- 經典面試題:強引用、軟引用、弱引用、虛引用有什麼區別?
- 面試官:線程有幾種狀態?他們是如何相互轉換的?
·END·
掃描二維碼 | 關注咱們