【并发编程】- 多个CountDownLatch 线程集合同步点

709 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情

接着上一篇文章 【并发编程】- CountDownLatch 多线程集合同步点

虽然按预期运行成功,但并不能保证在main主线程中执行了service.startMatch()时,所有的工作线程都是wait状态,因为某些线程有可能准备的时间花费较长,可能耗用的时间超过2秒,这时如果在第2秒时调用service.startMatch()方法达不到“唤醒所有线程”继续向下运行的目的了,就是裁判员没有等全部的运动员到来时,就让发令枪响起开始比赛了,这是不符合逻辑,所以需要进行优化。

创建运动员线程代码如下:

public class Runner implements Runnable {

    private CountDownLatch comingTag; //裁判等待所有运动员到来
    private CountDownLatch waitTag; //等待裁判说准备开始
    private CountDownLatch waitRunTag; //等待起跑
    private CountDownLatch beginTag;//起跑
    private CountDownLatch endTag;//所有运动员到达终点

    public Runner(CountDownLatch comingTag,CountDownLatch waitTag,CountDownLatch waitRunTag,CountDownLatch beginTag,CountDownLatch endTag) {
        super();
        this.comingTag=comingTag;
        this.waitTag=waitTag;
        this.waitRunTag=waitRunTag;
        this.beginTag=beginTag;
        this.endTag=endTag;
    }


    @Override
    public void run() {
        try {
            System.out.println("运动员使用不同方式到达起跑点,正向这边走!");
            Thread.sleep((int)(Math.random()*1000));
            System.out.println("运动员"+Thread.currentThread().getName()+" 到起跑点了!  ");
            comingTag.countDown();
            System.out.println("等待裁判说准备!");
            waitTag.await();
            System.out.println("各就各位!准备起跑姿势! ");
            Thread.sleep((int)(Math.random()*1000));
            waitRunTag.countDown();
            beginTag.await();
            System.out.println("运动员"+Thread.currentThread().getName()+"起跑 并且跑过程用时不确定");
            Thread.sleep((int)(Math.random()*1000));
            endTag.countDown();
            System.out.println("运动员"+Thread.currentThread().getName()+"到达终点!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行类代码如下:

public class RunnerMatch {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch comingTag = new CountDownLatch(5);
        CountDownLatch waitTag = new CountDownLatch(1);
        CountDownLatch waitRunTag = new CountDownLatch(5);
        CountDownLatch beginTag = new CountDownLatch(1);
        CountDownLatch endTag = new CountDownLatch(5);
        Runner[] runners = new Runner[5];
        for (int i = 0; i <runners.length ; i++) {
            runners[i] = new Runner(comingTag, waitTag, waitRunTag, beginTag, endTag);
            new Thread(runners[i]).start();
        }
        System.out.println("裁判员在等待选手的到来!");
        comingTag.await();
        System.out.println("裁判员看到所有运动员来了,各就各位前巡视用时5秒");
        Thread.sleep(5000);
        waitTag.countDown();
        System.out.println("各就各位!");
        waitRunTag.await();
        Thread.sleep(2000);
        System.out.println("发令枪响起!");
        beginTag.countDown();
        endTag.await();
        System.out.println("所有运动员到达,统计比赛名次!");
    }
}

运行结果如下:

裁判员在等待选手的到来!
运动员使用不同方式到达起跑点,正向这边走!
运动员使用不同方式到达起跑点,正向这边走!
运动员使用不同方式到达起跑点,正向这边走!
运动员使用不同方式到达起跑点,正向这边走!
运动员使用不同方式到达起跑点,正向这边走!
运动员Thread-4 到起跑点了!  
等待裁判说准备!
运动员Thread-0 到起跑点了!  
等待裁判说准备!
运动员Thread-1 到起跑点了!  
等待裁判说准备!
运动员Thread-2 到起跑点了!  
等待裁判说准备!
运动员Thread-3 到起跑点了!  
等待裁判说准备!
裁判员看到所有运动员来了,各就各位前巡视用时5秒
各就各位!准备起跑姿势! 
各就各位!准备起跑姿势! 
各就各位!准备起跑姿势! 
各就各位!
各就各位!准备起跑姿势! 
各就各位!准备起跑姿势! 
发令枪响起!
运动员Thread-4起跑 并且跑过程用时不确定
运动员Thread-2起跑 并且跑过程用时不确定
运动员Thread-1起跑 并且跑过程用时不确定
运动员Thread-3起跑 并且跑过程用时不确定
运动员Thread-0起跑 并且跑过程用时不确定
运动员Thread-2到达终点!
运动员Thread-0到达终点!
运动员Thread-1到达终点!
运动员Thread-4到达终点!
运动员Thread-3到达终点!
所有运动员到达,统计比赛名次!