我们有时会使用java循环模拟并发请求,但for循环的实际情况是完成上一次循环后才进入本次循环,不同请求之间还是有细微的时间差,无法真正模拟出同时请求的场景。
我们把并发场景比作百米赛跑。现在假如有八名运动员参加百米赛,正常情况下裁判会等所有选手准备就绪后,扣响发令枪,所有运动员一起出发。我们以for循环来实现这一场景。
public class ForTestThread extends Thread {
public static void main(String[] args) {
for(int i = 1 ; i <= 8 ;i ++ ){
Thread thread = new ForTestThread(i);
thread.start();
}
}
private int num;
public ForTestThread(int num) {
this.num = num;
}
@Override
public void run() {
System.out.println("第"+num+"个选手已就位");
System.out.println("第"+num+"个选手已出发");
}
}
输出的结果为
可以看到实际是每个运动员准备好之后就出发了,不会等所有运动员就位,这样每个运动员的出发时间是不同的,并不能实现模拟并发的初衷。
为了模拟真正意义的并发,我们可以使用JDK提供的CountDownLatch实现,使用了CountDownLatch的代码如下
import java.util.concurrent.CountDownLatch;
public class TestThread extends Thread {
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(10);
for(int i = 1 ; i <= 10 ;i ++ ){
Thread thread = new TestThread(latch,i);
thread.start();
}
}
private CountDownLatch latch;
private int num;
public TestThread(CountDownLatch latch,int num) {
this.latch = latch;
this.num = num;
}
@Override
public void run() {
latch.countDown();
System.out.println("第"+num+"个选手已就位");
try {
latch.await();
System.out.println("第"+num+"个选手已出发");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果
可以看到所有运动员是在全部运动员就位之后才出发的,虽然打印出的内容看起来所有出发的运动员分了先后,但实际上所有的出发操作是在同一时间产生的。
代码中用到的countDown和await方法是CountDownLatch最重要的两个方法,可以把CountDownLatch比作是一个发令枪命令,在声明CountDownLatch时会传入一个int类型的参数,这个参数是倒计数的开始,每调一次countDown,倒计数减一,当倒计数减大于0时执行await方法代码会停止到当前行,等倒计数减为0时所有所有停止的代码会同时往后执行。