java并发-CountDownLatch模拟并发

最近在听腾讯课堂一些java架构师的公开课,发现有些老师写的代码模拟并发,并不是太严谨,模拟并发用的下边第一种方式。但是这样不能有效的模拟并发场景。个人理解的,用countdownlatch模拟并发 , 并发线程里应该await(), 在主线程里countdown(), 这就好比,田径赛跑,各线程准备好后,await住, 等待主线程从10数到0时(countdown), 所有线程开始跑。这样才能正确模拟并发。

自己分析了以下两种场景写法:

场景一:

/**

 * 模拟10个线程准备,10个都准备好后,主线程才开始运行
 * 
 * @author nightrain
 *
 */
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();
}

}

场景二:模拟并发

/**
 * 模拟10并发,尽量保持同一时刻放开运行,这样才真实。
 * 
 * @author nightrain
 *
 */


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....

时间戳证明这些并发线程应该是同一时刻又并发执行的


你可能感兴趣的:(Java)