標籤:
首先從公司一道筆試題開始
1 package test; 2 3 public class Test implements Runnable { 4 5 public int i = 0; 6 7 @Override 8 public void run() { 9 try {10 Thread.sleep(1000);11 } catch (InterruptedException e) {12 // TODO Auto-generated catch block13 e.printStackTrace();14 }15 i = 10;16 }17 18 public static void main(String[] args) {19 try {20 Test t = new Test();21 Thread th = new Thread(t);22 th.start();23 th.join();24 System.out.println(t.i);25 } catch (Exception ex) {26 27 }28 29 }30 }
問23行代碼怎麼寫,才能讓24行列印出10?
不少筆試者會選t.wait()或者th.wait()!
面試的時候問他為什麼,他具體也說不清楚,感覺就是見過這個wait方法,但是wait方法的含義確一知半解。
wait 是什麼意思呢?我舉例子啊,比如我想讓本線程放棄當前對象鎖,說直白點就是讓別的對象進入同步塊
1 package test; 2 3 public class Test implements Runnable { 4 5 public Object i = new Object(); 6 7 @Override 8 public void run() { 9 synchronized (i) {10 System.out.println(Thread.currentThread().getName()+"enter ");11 // i.notify();12 try {13 i.wait();14 } catch (InterruptedException e) {15 // TODO Auto-generated catch block16 e.printStackTrace();17 }18 System.out.println(Thread.currentThread().getName()+"out ");19 }20 }21 22 public static void main(String[] args) {23 try {24 Test t = new Test();25 Thread th1 = new Thread(t);26 Thread th2 = new Thread(t);27 th1.start();28 th2.start();29 30 31 } catch (Exception ex) {32 33 }34 35 }36 }
如上例,你會看到輸出
Thread-0enter
Thread-1enter
不會看到
Thread-1out
Thread-0out
因為Thread-0 先獲得了Object i 鎖,然後運行到13行,釋放了該鎖,
這個時候Thread-1就獲得了Object i 鎖,進入了同步代碼塊,然後同樣運行13行,也釋放了該鎖。
這個時候在有兩個線程Thread-0和Thread-1等待獲得Object i 鎖,由於代碼中沒有調用i.notifyAll(),所以這個程式永遠不會退出。
但是如果開啟注釋11行,那麼你將會看到結果
Thread-0enter
Thread-1enter
Thread-0out
因為Thread-0 先獲得了Object i 鎖,然後運行到13行,釋放了該鎖,
這個時候Thread-1就獲得了Object i 鎖,進入了同步代碼塊,運行到11行,i.notify(),
那麼這個意思就是說別的等待i鎖的線程可以喚醒了,一旦我(Thread-1)釋放鎖(13行調用wait()),那麼Thread-0就可以獲得i鎖繼續執行了。
此程式中沒有在Thread-1 釋放i鎖(wait())之後notify,所以永遠不會看到Thread-1out
再回到這個題目,我們的意思是讓主線程等待所有子線程執行完畢 ,再執行。更何況筆試題中沒有鎖對象。更別提wait()了。
所以,此處應該用th.join(); Thread.join()方法會阻塞主線程繼續向下執行。
1 public class TestThread extends Thread 2 { 3 private CountDownLatch countDownLatch; 4 5 public TestThread(CountDownLatch countDownLatch) 6 { 7 this.countDownLatch = countDownLatch; 8 } 9 10 public void run() 11 { 12 System.out.println(this.getName() + "子線程開始"); 13 try 14 { 15 // 子線程休眠五秒 16 Thread.sleep(5000); 17 } 18 catch (InterruptedException e) 19 { 20 e.printStackTrace(); 21 }22 23 System.out.println(this.getName() + "子線程結束");24 25 // 倒數器減126 countDownLatch.countDown();27 }28 }
1 public class Main 2 { 3 public static void main(String[] args) 4 { 5 long start = System.currentTimeMillis(); 6 7 // 建立一個初始值為5的倒數計數器 8 CountDownLatch countDownLatch = new CountDownLatch(5); 9 for(int i = 0; i < 5; i++)10 {11 Thread thread = new TestThread(countDownLatch);12 thread.start();13 }14 15 try16 {17 // 阻塞當前線程,直到倒數計數器倒數到018 countDownLatch.await();19 }20 catch (InterruptedException e)21 {22 e.printStackTrace();23 }24 25 long end = System.currentTimeMillis();26 System.out.println("子線程執行時間長度:" + (end - start));27 }28 }
Java多線程--讓主線程等待所有子線程執行完畢 join