多線程應用中,經常會遇到這種場景:後面的處理,依賴前面的N個線程的處理結果,必須等前面的線程執行完畢後,後面的代碼才允許執行。
在我不知道CyclicBarrier之前,最容易想到的就是放置一個公用的static變量,假如有10個線程,每個線程處理完上去累加下結果,然後後面用一個死循環(或類似線程阻塞的方法),去數這個結果,達到10個,說明大家都爽完了,可以進行後續的事情了,這個想法雖然土鼈,但是基本上跟語言無關,幾乎所有主流程式設計語言都支援。
輸出結果:
thread 0 done
thread 0 => 1
thread 9 done
thread 9 => 2
thread 1 done
thread 1 => 3
thread 3 done
thread 3 => 4
thread 7 done
thread 7 => 5
thread 6 done
thread 6 => 6
thread 2 done
thread 2 => 7
thread 4 done
thread 4 => 8
thread 8 done
thread 8 => 9
thread 5 done
thread 5 => 10
-----------
所有thread執行完成!
除了這個方法,還可以借助FutureTask,達到類似的效果,其get方法會阻塞線程,等到該異步處理完成。缺點就是,FutureTask調用的是Callable,必須要有傳回值,是以就算你不想要傳回值,也得傳回點啥
執行結果:
task0 done
task1 done
task2 done
task3 done
task4 done
task5 done
task6 done
task7 done
task8 done
task9 done
所有task執行完成!
此外,Thread的Join方法也可以實作類似的效果,主要代碼如下:
當然,這個需求最“正統”的解法應該是使用CyclicBarrier,它可以設定一個所謂的“屏障點”(或稱集合點),好比在一項團隊活動中,每個人都是一個線程,但是規定某一項任務開始前,所有人必須先到達集合點,集合完成後,才能繼續後面的任務。
thread 9 done,正在等候其它線程完成...
thread 5 done,正在等候其它線程完成...
thread 0 done,正在等候其它線程完成...
thread 6 done,正在等候其它線程完成...
thread 4 done,正在等候其它線程完成...
thread 2 done,正在等候其它線程完成...
thread 3 done,正在等候其它線程完成...
thread 8 done,正在等候其它線程完成...
thread 7 done,正在等候其它線程完成...
thread 1 done,正在等候其它線程完成...
參考文章:
<a href="http://ifeve.com/concurrency-cyclicbarrier/" target="_blank">http://ifeve.com/concurrency-cyclicbarrier/</a>
<a href="http://ifeve.com/thread-synchronization-utilities-5/" target="_blank">http://ifeve.com/thread-synchronization-utilities-5/</a>
<a href="http://ifeve.com/thread-management-7/" target="_blank">http://ifeve.com/thread-management-7/</a>