CountDownLatch和CyclicBarrier用法及例子

CountDownLatch和CyclicBarrier用法及例子

1.都是用来实现其他任务都完成后,然后再执行一个任务的需求,类似赛跑比赛,需要等所有运动员到达终点后,才能开始下一步颁奖。
2.CountDownLatch是一次性的,不能重复使用;CyclicBarrier是可重复的;
3.CountDownLatch使用时,在每个需要等待的地方调用await,在每个触发条件的地方调用countDown即可,countDown次数达到指定次数,会唤醒所有await;
4.CyclicBarrier使用时,在每个需要等待的地方调用await,然后内部会自动统计await次数,到达指定次数后,自动回调,完成回调后,唤醒所有await。

例子1,每个任务计算一个值,都完成计算后进行下一步计算。Test2模拟了普通的计算任务,都完成后,会从latch.await()那个地方继续执行:
public class Main {
private static final int N = 5;

public static final void main(String[] args) {
    testCountDownLatch();
}

private static void testCountDownLatch() {
    CountDownLatch latch = new CountDownLatch(N);
    Test2[] tt = new Test2[N];
    for (int i = 0; i < N; i++) {
        tt[i] = new Test2(latch);
        new Thread(tt[i]).start();
    }
    System.out.println("Main is Wait.");
    try {
        latch.await();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    int total = 0;
    for (int i = 0; i < N; i++) {
        total += tt[i].ret;
    }
    System.out.println("Main is Wait Over!" + total);
}

}

public class Test2 implements Runnable {
private CountDownLatch latch;

public Test2(CountDownLatch latch) {
    this.latch = latch;
}

public int ret = 0;

@Override
public void run() {
    System.out.println("Thread-" + Thread.currentThread().getName() + " is Running");
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    ret = 1;
    System.out.println("Thread-" + Thread.currentThread().getName() + " is finish Task!");
    latch.countDown();

}

}

输出结果:
Thread-Thread-1 is Running
Thread-Thread-2 is Running
Thread-Thread-3 is Running
Main is Wait.
Thread-Thread-4 is Running
Thread-Thread-0 is Running
Thread-Thread-2 is finish Task!
Thread-Thread-4 is finish Task!
Thread-Thread-3 is finish Task!
Thread-Thread-1 is finish Task!
Thread-Thread-0 is finish Task!
Main is Wait Over!5

例子2,用CountDownLatch实现的一个运动员比赛的程序:
public class Main {
// 运动员数量
private static final int N = 5;

public static final void main(String[] args) {
    testCountDownLatch2();
}

private static void testCountDownLatch2() {
    // 运动员准备好的信号
    CountDownLatch latchStart = new CountDownLatch(N);
    // 运动员都完成比赛的信号
    CountDownLatch latchOver = new CountDownLatch(N);
    // 正式开始比赛的信号
    CountDownLatch startSignal = new CountDownLatch(1);
    for (int i = 0; i < N; i++) {
        new Thread(new Player(i, latchStart, latchOver, startSignal)).start();
    }
    System.out.println("等待运动员都准备好");
    try {
        // 等待运动员都准备好
        latchStart.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("开始比赛");
    // 开始比赛信号
    startSignal.countDown();
    try {
        // 等待所有运动员完成比赛
        latchOver.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("所有运动员都完成了比赛,比赛结束");
}

}

public class Player implements Runnable {
private CountDownLatch latchStart;
private CountDownLatch latchOver;
private CountDownLatch startSignal;

private int id;

private static Random sRandom = new Random();

public Player(int id, CountDownLatch latchStart, CountDownLatch latchOver, CountDownLatch startSignal) {
    this.id = id;
    this.latchStart = latchStart;
    this.latchOver = latchOver;
    this.startSignal = startSignal;
}

@Override
public void run() {
    // 模拟准备时间
    try {
        Thread.sleep(sRandom.nextInt(2000));
    } catch (InterruptedException e2) {
        e2.printStackTrace();
    }
    System.out.println("Player" + id + "准备好" + System.currentTimeMillis());
    // 运动员准备好
    this.latchStart.countDown();
    try {
        // 等待裁判说开始
        this.startSignal.await();
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }
    System.out.println("Player" + id + " 开始跑" + System.currentTimeMillis());
    long duration = sRandom.nextInt(5000);
    try {
        // 模拟跑的时间
        Thread.sleep(duration);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("Player" + id + " 完成比赛,耗时:" + duration);
    // 运动员完成比赛
    this.latchOver.countDown();
}

}

输出结果:
等待运动员都准备好
Player0准备好1508221461341
Player2准备好1508221461832
Player3准备好1508221462335
Player4准备好1508221462369
Player1准备好1508221463031
开始比赛
Player0 开始跑1508221463032
Player4 开始跑1508221463032
Player3 开始跑1508221463032
Player2 开始跑1508221463032
Player1 开始跑1508221463032
Player1 完成比赛,耗时:1202
Player2 完成比赛,耗时:1939
Player0 完成比赛,耗时:1947
Player4 完成比赛,耗时:2878
Player3 完成比赛,耗时:3974
所有运动员都完成了比赛,比赛结束

例子3,用CyclicBarrier实现例子1:
public class Main {
private static final int N = 5;

public static final void main(String[] args) {
    testCyclicBarrier();
}

private static void testCyclicBarrier() {
    Test3[] tt = new Test3[N];
    CyclicBarrier barrier = new CyclicBarrier(N, new Runnable() {

        @Override
        public void run() {
            // await达到指定次数,随机选一个线程来执行这个任务
            System.out.println("Barrier All Task Finished,CurrentThread=" + Thread.currentThread().getName());
            int total = 0;
            for (int i = 0; i < N; i++) {
                total += tt[i].ret;
            }
            System.out.println("计算结果是:" + total);
        }
    });
    for (int i = 0; i < N; i++) {
        tt[i] = new Test3(barrier);
        new Thread(tt[i]).start();
    }
}

}

public class Test3 implements Runnable {
private CyclicBarrier barrier;

public Test3(CyclicBarrier barrier) {
    this.barrier = barrier;
}

public int ret = 0;

@Override
public void run() {
    System.out.println("Thread-" + Thread.currentThread().getName() + " is Running");
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    ret = 1;
    System.out.println("Thread-" + Thread.currentThread().getName() + " is finish Task!");
    try {
        this.barrier.await();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("Thread-" + Thread.currentThread().getName() + " exit!");

}

}

输出结果:
Thread-Thread-1 is Running
Thread-Thread-0 is Running
Thread-Thread-3 is Running
Thread-Thread-4 is Running
Thread-Thread-2 is Running
Thread-Thread-3 is finish Task!
Thread-Thread-2 is finish Task!
Thread-Thread-1 is finish Task!
Thread-Thread-0 is finish Task!
Thread-Thread-4 is finish Task!
Barrier All Task Finished,CurrentThread=Thread-4
计算结果是:5
Thread-Thread-4 exit!
Thread-Thread-3 exit!
Thread-Thread-0 exit!
Thread-Thread-1 exit!
Thread-Thread-2 exit!

例子4,用CyclicBarrier实现例子2:
public class Main {
private static final int N = 5;

public static final void main(String[] args) {
    testCyclicBarrier2();
}

private static void testCyclicBarrier2() {
    CyclicBarrier barrierPrepare = new CyclicBarrier(N, new Runnable() {

        @Override
        public void run() {
            // 准备完成
            System.out.println("所有运动员准备完毕,开始比赛");
            
        }
    });
    CyclicBarrier barrierOver = new CyclicBarrier(N, new Runnable() {

        @Override
        public void run() {
            // 比赛完成
            System.out.println("所有运动员比赛都完成了,结束比赛");
        }
    });
    for (int i = 0; i < N; i++) {
        new Thread(new Player2(i, barrierPrepare, barrierOver)).start();
    }
}

}

public class Player2 implements Runnable {
private CyclicBarrier barrierPrepared;
private CyclicBarrier barrierOver;
private int id;
private static Random sRandom = new Random();

public Player2(int id, CyclicBarrier barrierPrepared, CyclicBarrier barrierOver) {
    this.barrierPrepared = barrierPrepared;
    this.barrierOver = barrierOver;
    this.id = id;
}

public void run() {
    try {
        // 模拟准备比赛
        Thread.sleep(sRandom.nextInt(3000));
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("运动员" + id + "准备比赛");
    try {
        // 等待开始
        barrierPrepared.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        e.printStackTrace();
    }
    System.out.println("运动员" + id + "开始比赛" + System.currentTimeMillis());
    int duration = sRandom.nextInt(5000);
    try {
        // 模拟比赛耗时
        Thread.sleep(duration);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("运动员" + id + "完成比赛,比赛时长:" + duration);
    try {
        // 等待比赛结束
        barrierOver.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        e.printStackTrace();
    }

}

}

输出结果:
运动员2准备比赛
运动员0准备比赛
运动员1准备比赛
运动员4准备比赛
运动员3准备比赛
所有运动员准备完毕,开始比赛
运动员3开始比赛1508222334484
运动员2开始比赛1508222334484
运动员1开始比赛1508222334484
运动员0开始比赛1508222334484
运动员4开始比赛1508222334484
运动员4完成比赛,比赛时长:777
运动员0完成比赛,比赛时长:2640
运动员1完成比赛,比赛时长:2952
运动员3完成比赛,比赛时长:3843
运动员2完成比赛,比赛时长:3924
所有运动员比赛都完成了,结束比赛

你可能感兴趣的:(CountDownLatch和CyclicBarrier用法及例子)