一:說明
基本上對於線程初步了解的人,都是使用synchronized來同步線程的,也確實,它也是可以滿足一些常用的問題。那么我們來說一些它不能解決的問題(其實是不怎么好解決的問題,並不是真的不能解決)
1.1:場景一
問題:
在一場運動會上,有10個運動員,只有當10個運動員都准備完畢后,所有人才能一起跑,否則就算前面的運動員在幾天前都做好准備了,只要最后一個運動員沒有做好准備,那所有的人都不能跑,有失公平嘛!
常規的解決方法
定義一個計數器,並且對它的操作進行同步,當每有一個准備完畢后,增加這個計數器的准備好的數量,當達到10個的時候,全部一起運行,那么大概的代碼是這樣子的,程序要定義一個死循環,只有當所有的條件滿足的時候,才能往下走,否則就一直循環。
1.2:場景二:多線程下載文件,我們使用它來作為例子
為了提高下載效率,充分利用網絡資源,決定使用多線程來下載一個文件,那么每一個線程分別下載一小段文件,當所有的文件下載完之后,對所有的文件進行合並,那就得到完整的文件了。
理論上來說代碼是這樣子的(理論上,實際上是錯誤的)
public static void go(){ System.out.println("開始下載文件,開啟10個線程下載"); for(int i = 0 ; i < 10 ; i ++){ new Thread(){ public void run(){ System.out.println("文件下載完成"); } }.start(); } //開始合並文件 System.out.println("所有文件下載完成,開始合並文件"); }
上面的代碼開啟了10個線程去下載文件,下載完之后,執行合並文件的方法,但是由於多線程,合並文件的時候,線程肯定是沒有執行完成的。
要怎么辦呢?這個時候命名用synchronized肯定是沒用的,synchronized只是使得同一時間只有一個線程通過
二:CountDownLatch使用所有的線程等待。
CountDownLatch這個類,可以使得所有的線程,全部停在那一個位置,達到指定的條件的時候,才可以運行。先給出代碼
public static void main(String[] args) throws Exception { //這里的構造方法參數是指需要達到完成的數量個數 final CountDownLatch cd = new CountDownLatch(10); for(int i = 0 ; i < 10 ; i ++){ new Thread(){ public void run(){ System.out.println("文件下載完成"); //還記得之前構造方法的參數嗎,10,每調用一個countDown()方法,都會使得這個數值減1 cd.countDown(); } }.start(); } //這個方法,會使得所有的線程暫停,只有當cd構造方法里面的值為0的時候,才能走通,調用一個countDown()方法,都會使得這個數值減1 cd.await(); //或者使用這個方法,這個方法也會等待數值到0才會往下面走,但是如果達到指定的時間,還沒有達到0,它也會走過 // cd.await(1000, TimeUnit.MINUTES); //開始合並文件 System.out.println("所有文件下載完成,開始合並文件"); }
執行結果是這樣的
文件下載完成
文件下載完成
文件下載完成
文件下載完成
文件下載完成
文件下載完成
文件下載完成
文件下載完成
文件下載完成
文件下載完成
所有文件下載完成,開始合並文件
這樣就滿足條件啦