初識CountDownLatch
標(biāo)簽:并發(fā)
原文鏈接:初識CountDownLatch 轉(zhuǎn)載請注明出處~
CountDownLatch是什么
在java.util.concurrent包內(nèi)。CountDownLatch是一個(gè)同步工具類角虫,允許一個(gè)或多個(gè)線程一直等待拙毫,直等到其他線程的某些操作執(zhí)行完成后再繼續(xù)執(zhí)行卵凑。
CountDownLatch是在java1.5被引入的叫挟,跟它一起被引入的并發(fā)工具類還有CyclicBarrier双炕、Semaphore踱蠢、ConcurrentHashMap和BlockingQueue袖肥,它們都存在于java.util.concurrent包下咪辱。CountDownLatch這個(gè)類能夠使一個(gè)線程等待其他線程完成各自的工作后再執(zhí)行
CountDownLatch如何工作
CountDownLatch是通過一個(gè)計(jì)數(shù)器來實(shí)現(xiàn)的,計(jì)數(shù)器的初始值為線程的數(shù)量椎组。每當(dāng)一個(gè)線程完成了自己的任務(wù)后油狂,計(jì)數(shù)器的值就會減1。當(dāng)計(jì)數(shù)器值到達(dá)0時(shí)寸癌,它表示所有的線程已經(jīng)完成了任務(wù)专筷,然后在閉鎖上等待的線程就可以恢復(fù)執(zhí)行任務(wù)。
CountDownLatch偽代碼
//Main thread start
//Create CountDownLatch for N threads
//Create and start N threads
//Main thread wait on latch
//N threads completes there tasks are returns
//Main thread resume execution
CountDownLatch.java類中定義的構(gòu)造函數(shù):
//Constructs a CountDownLatch initialized with the given count.
public void CountDownLatch(int count) {...}
構(gòu)造器中的計(jì)數(shù)器(count)是實(shí)際上閉鎖需要等待的線程數(shù)量蒸苇。這個(gè)值只能被設(shè)置一次磷蛹,CountDownLatch沒有提供任何機(jī)制去重新設(shè)置這個(gè)值
與CountDownLatch的第一次交互是主線程等待其他線程,主線程必須在啟動其他線程后立即調(diào)用CountDownLatch.await()方法填渠。這樣主線程的操作會在這個(gè)方法上阻塞弦聂,直到其他線程完成各自的任務(wù)鸟辅。
其他N個(gè)線程必須引用閉鎖對象氛什,因?yàn)樗麄冃枰ㄖ狢ountDownLatch對象莺葫,他們已經(jīng)完成了各自的任務(wù)。這種通知機(jī)制是通過 CountDownLatch.countDown()方法來完成的枪眉;每調(diào)用一次這個(gè)方法捺檬,在構(gòu)造函數(shù)中初始化的count值就減1。所以當(dāng)N個(gè)線程都調(diào) 用了這個(gè)方法贸铜,count的值等于0堡纬,然后主線程就能通過await()方法,恢復(fù)執(zhí)行自己的任務(wù)蒿秦。
主要方法
// Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted.
void await()
// Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted, or the specified waiting time elapses.
boolean await(long timeout, TimeUnit unit)
void countDown()
Decrements the count of the latch, releasing all waiting threads if the count reaches zero.
long getCount()
Returns the current count.
String toString()
Returns a string identifying this latch, as well as its state.
一個(gè)例子
在這個(gè)例子中烤镐,我模擬了一個(gè)應(yīng)用程序啟動類,它開始時(shí)啟動了n個(gè)線程類棍鳖,這些線程將檢查外部系統(tǒng)并通知閉鎖炮叶,并且啟動類一直在閉鎖上等待著。一旦驗(yàn)證和檢查了所有外部服務(wù)渡处,那么啟動類恢復(fù)執(zhí)行镜悉。
BaseHealthChecker.java:這個(gè)類是一個(gè)Runnable,負(fù)責(zé)所有特定的外部服務(wù)健康的檢測医瘫。它刪除了重復(fù)的代碼和閉鎖的中心控制代碼侣肄。
public abstract class BaseHealthChecker implements Runnable {
private CountDownLatch _latch;
private String _serviceName;
private boolean _serviceUp;
//Get latch object in constructor so that after completing the task, thread can countDown() the latch
public BaseHealthChecker(String serviceName, CountDownLatch latch)
{
super();
this._latch = latch;
this._serviceName = serviceName;
this._serviceUp = true;
}
@Override
public void run() {
try {
verifyService();
_serviceUp = true;
} catch (Throwable t) {
t.printStackTrace(System.err);
_serviceUp = false;
} finally {
if(_latch != null) {
_latch.countDown();
}
}
}
public String getServiceName() {
return _serviceName;
}
public boolean isServiceUp() {
return _serviceUp;
}
//This methos needs to be implemented by all specific service checker
public abstract void verifyService();
}
NetworkHealthChecker.java:這個(gè)類繼承了BaseHealthChecker,實(shí)現(xiàn)了verifyService()方法醇份。DatabaseHealthChecker.java和CacheHealthChecker.java除了服務(wù)名和休眠時(shí)間外稼锅,與NetworkHealthChecker.java是一樣的。
public class NetworkHealthChecker extends BaseHealthChecker
{
public NetworkHealthChecker (CountDownLatch latch) {
super("Network Service", latch);
}
@Override
public void verifyService()
{
System.out.println("Checking " + this.getServiceName());
try
{
Thread.sleep(7000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(this.getServiceName() + " is UP");
}
}
ApplicationStartupUtil.java:這個(gè)類是一個(gè)主啟動類僚纷,它負(fù)責(zé)初始化閉鎖缰贝,然后等待,直到所有服務(wù)都被檢測完畔濒。
public class ApplicationStartupUtil
{
//List of service checkers
private static List<BaseHealthChecker> _services;
//This latch will be used to wait on
private static CountDownLatch _latch;
private ApplicationStartupUtil()
{
}
private final static ApplicationStartupUtil INSTANCE = new ApplicationStartupUtil();
public static ApplicationStartupUtil getInstance()
{
return INSTANCE;
}
public static boolean checkExternalServices() throws Exception
{
//Initialize the latch with number of service checkers
_latch = new CountDownLatch(3);
//All add checker in lists
_services = new ArrayList<BaseHealthChecker>();
_services.add(new NetworkHealthChecker(_latch));
_services.add(new CacheHealthChecker(_latch));
_services.add(new DatabaseHealthChecker(_latch));
//Start service checkers using executor framework
Executor executor = Executors.newFixedThreadPool(_services.size());
for(final BaseHealthChecker v : _services)
{
executor.execute(v);
}
//Now wait till all services are checked
_latch.await();
//Services are file and now proceed startup
for(final BaseHealthChecker v : _services)
{
if( ! v.isServiceUp())
{
return false;
}
}
return true;
}
}
現(xiàn)在你可以寫測試代碼去檢測一下閉鎖的功能了剩晴。
public class Main {
public static void main(String[] args)
{
boolean result = false;
try {
result = ApplicationStartupUtil.checkExternalServices();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("External services validation completed !! Result was :: "+ result);
}
}
Output in console:
Checking Network Service
Checking Cache Service
Checking Database Service
Database Service is UP
Cache Service is UP
Network Service is UP
External services validation completed !! Result was :: true
參考文獻(xiàn)
That's all,enjoy it~歡迎訪問博主個(gè)人博客:http://kongdehui.com/ ~~~