Java並發工具類之CountDownLatch
CountDownLatch允許一個或則多個線程等待其他線程完成操作。
假如我們有這樣的需求:我們需要解析一個excel文件中的多個sheet,我們可以考慮使用多線程,每一個線程解析excel中的一個sheet表格,等所有的線程都完成解析之後,程序提示解析完成,輸出解析結果。要實現這個需求,最簡單的方式是使用Thread類的join方法,等待所有的線程都完成解析之後再提示解析完成,我們可以用一下代碼完成解析:
public class ReadExcelSheetsUserThreadJoinTest { public static void main(String[] args) throws InterruptedException { Thread sheet1Thread= new Thread(new Runnable() { @Override public void run() { System.out.println("解析sheet1"); } }); Thread sheet2Thread = new Thread(new Runnable() { @Override public void run() { System.out.println("解析sheet2"); } }); sheet1Thread.start(); sheet2Thread.start(); sheet1Thread.join(); sheet2Thread.join(); System.out.print("所有的表格解析完成"); } }
輸出結果:
解析sheet1
解析sheet2
所有的表格解析完成
join用於讓當前執行線程等待join線程執行結束,其執行原理是不停的檢查join線程是否存活,如果join線程存活,則讓當前線程永遠等待。代碼如下,其中wait(0)表示永遠等待。
while (isAlive()) { wait(0); }
直到join線程終止後,線程的this.notifyAll()方法被調用,大家可以參考JVM源碼,查看notifyAll方法被調用的過程。
在JDK1.5之後,Java的並發包提供了CountDownLatch,CountDownLatch也可以實現線程的join功能,並且比Thread的join方法提供的功能更多,使用CountDownLatch實現上述需求的代碼如下:
public class ReadExcelSheetsUseCountDownLatchTest { private static CountDownLatch countDownLatch = new CountDownLatch(2); public static void main(String[] args) throws InterruptedException { Thread sheet1Thread = new Thread(new Runnable() { @Override public void run() { System.out.println("解析sheet1"); countDownLatch.countDown(); } }); Thread sheet2Thread = new Thread(new Runnable() { @Override public void run() { System.out.println("解析sheet2"); countDownLatch.countDown(); } }); sheet1Thread.start(); sheet2Thread.start(); countDownLatch.await(); System.out.print("所有的表格解析完成"); } }
CountDownLatch的構造函數接收一個int類型的參數作為計數器,如果你想等待n個點完成,就傳入n,我們調用CountDownLatch的countDown方法的時候,n就會減1,await方法會阻塞當前線程直到n變為0,由於CountDownLatch的countDown方法可以用在任何地方,因此這裏的n可以是n個線程,也可以是1個線程裏面的n個步驟。編程的時候只需要把CountDownLatch的引用傳到線程即可。
有時候,我們不希望執行線程一直等待下去,這個時候我們可以使用CountDownLatch的await(long time,TimeUnit unit),這個方法在特定的時間之後就不會再阻塞執行線程,當然join也有類似的重載方法。
計數器必須大於等於0,只是等於0時候,計數器就是零,調用await方法時不會阻塞當前線程。CountDownLatch不可能重新初始化或者修改CountDownLatch對象的內部計數器的值。一個線程調用countDown方法happen-before,另外一個線程調用await方法。
Java並發工具類之CountDownLatch