天天看點

java并發-CountDownLatch模拟并發

最近在聽騰訊課堂一些java架構師的公開課,發現有些老師寫的代碼模拟并發,并不是太嚴謹,模拟并發用的下邊第一種方式。但是這樣不能有效的模拟并發場景。個人了解的,用countdownlatch模拟并發 , 并發線程裡應該await(), 在主線程裡countdown(), 這就好比,田徑賽跑,各線程準備好後,await住, 等待主線程從10數到0時(countdown), 所有線程開始跑。這樣才能正确模拟并發。

自己分析了以下兩種場景寫法:

場景一:

public class TestCountDownLatch1 {

public static void main(String[] args) throws InterruptedException

{

int threadCount = 10;

ExecutorService es =  Executors.newFixedThreadPool(threadCount);

CountDownLatch cdl = new CountDownLatch(threadCount);

for (int i = 0; i < threadCount; i++)

{

es.execute(new Runnable(){

@Override

public void run() {

System.out.println("目前線程:" + Thread.currentThread().getName() + "準備....");

//模拟準備500ms

try {

Thread.sleep(500);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

finally

{

System.out.println("目前線程:" + Thread.currentThread().getName() + "已就緒...., countdown減一.");

cdl.countDown();

}

}

});

}

System.out.println("主線程:" + Thread.currentThread().getName() + "等待其他線程,同時到達某一狀态,即countdown為0....");

cdl.await();

System.out.println("主線程:" + Thread.currentThread().getName() + "等待結束, 開始運作...");

es.shutdown();

}

}

場景二:模拟并發

public class TestCountDownLatch2 {

public static void main(String[] args) throws InterruptedException 

{

int threadCount = 10;

ExecutorService es =  Executors.newFixedThreadPool(threadCount);

CountDownLatch cdl = new CountDownLatch(threadCount);

for (int i = 0; i < threadCount; i++)

{

es.execute(new Runnable(){

@Override

public void run(){

System.out.println("目前線程:" + Thread.currentThread().getName() + "準備就緒, 等待countdown為0後開始運作....");

try {

cdl.await();

} catch (InterruptedException e1) {

}

finally

{

System.out.println("目前線程:" + Thread.currentThread().getName() + "等待結束, 開始模拟web使用者請求, 開始時間:" + System.currentTimeMillis());

}

//模拟準備500ms

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

finally

{

System.out.println("目前線程:" + Thread.currentThread().getName() + "模拟over....");

}

}

});

}

//等待兩秒,等待并發線程初始化完成。

Thread.sleep(2000);

System.out.println("主線程:" + Thread.currentThread().getName() + "countdown自減開始。。。");

for (int j = 0; j < threadCount; j++)

{

cdl.countDown();

}

System.out.println("主線程:" + Thread.currentThread().getName() + "countdown自減完成。。。");

es.shutdown();

}

}

輸出如下:

目前線程:pool-1-thread-1準備就緒, 等待countdown為0後開始運作....

目前線程:pool-1-thread-6準備就緒, 等待countdown為0後開始運作....

目前線程:pool-1-thread-4準備就緒, 等待countdown為0後開始運作....

目前線程:pool-1-thread-8準備就緒, 等待countdown為0後開始運作....

目前線程:pool-1-thread-10準備就緒, 等待countdown為0後開始運作....

目前線程:pool-1-thread-2準備就緒, 等待countdown為0後開始運作....

目前線程:pool-1-thread-3準備就緒, 等待countdown為0後開始運作....

目前線程:pool-1-thread-5準備就緒, 等待countdown為0後開始運作....

目前線程:pool-1-thread-7準備就緒, 等待countdown為0後開始運作....

目前線程:pool-1-thread-9準備就緒, 等待countdown為0後開始運作....

主線程:maincountdown自減開始。。。

目前線程:pool-1-thread-8等待結束, 開始模拟web使用者請求, 開始時間:1526568763776

主線程:maincountdown自減完成。。。

目前線程:pool-1-thread-1等待結束, 開始模拟web使用者請求, 開始時間:1526568763776

目前線程:pool-1-thread-10等待結束, 開始模拟web使用者請求, 開始時間:1526568763777

目前線程:pool-1-thread-6等待結束, 開始模拟web使用者請求, 開始時間:1526568763776

目前線程:pool-1-thread-2等待結束, 開始模拟web使用者請求, 開始時間:1526568763777

目前線程:pool-1-thread-4等待結束, 開始模拟web使用者請求, 開始時間:1526568763776

目前線程:pool-1-thread-5等待結束, 開始模拟web使用者請求, 開始時間:1526568763777

目前線程:pool-1-thread-3等待結束, 開始模拟web使用者請求, 開始時間:1526568763777

目前線程:pool-1-thread-7等待結束, 開始模拟web使用者請求, 開始時間:1526568763778

目前線程:pool-1-thread-9等待結束, 開始模拟web使用者請求, 開始時間:1526568763778

目前線程:pool-1-thread-8模拟over....

目前線程:pool-1-thread-1模拟over....

目前線程:pool-1-thread-6模拟over....

目前線程:pool-1-thread-2模拟over....

目前線程:pool-1-thread-10模拟over....

目前線程:pool-1-thread-4模拟over....

目前線程:pool-1-thread-5模拟over....

目前線程:pool-1-thread-9模拟over....

目前線程:pool-1-thread-7模拟over....

目前線程:pool-1-thread-3模拟over....

時間戳證明這些并發線程應該是同一時刻又并發執行的