最近在聽騰訊課堂一些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....
時間戳證明這些并發線程應該是同一時刻又并發執行的