java并发之同步工具类一之闭锁Latch

本文详细介绍了Java中闭锁(Latch)的概念与应用场景,并通过一个跑步比赛的例子展示了如何使用闭锁来确保所有线程都在同一时刻开始执行。

java同步工具类(指jdk1.5版本)主要有闭锁(Latch)、信号灯(semaphore)和栅栏(barrier)。本篇作为开篇,先讲闭锁。闭锁就相当于一扇门,在制定的线程到达后这扇门才打开,后续所有线程可以通过,否则就一直处于阻塞状态。用于确保某些活动(这里可以理解为子线程)都完成后再继续执行下去(主线程)。如游戏中所有玩家就绪后才能点击开始,测试并发代码块真正的执行时间等(当我们在测试多线程的时候,总会有部分线程先启动,部分后启动,毕竟创建线程本身也需要时间,也就是多个线程会处在不同的初始条件下,这样测试出来的执行时间会有偏差,特别是线程非常多的时候,而闭锁可以在先启动的线程会等到所有后面启动的线程都启动完毕后再一起开始)。
如下面的代码引用了一个同样的场景——跑步比赛,只有所有运动员sprotMan都准备就绪后,裁判judge才能执行开始比赛。当所有运动员都结束比赛(到达终点或者放弃比赛),整场比赛才算结束。

import java.util.concurrent.CountDownLatch;

/**
 *
 * @author Jerry 比赛与Latch
 * @date 2017/12/24 0024
 */
public class Judge {
    public static void main(String[] args) {
        int joinMatchCnt = 5;//参加比赛的人数
        CountDownLatch beginMatchFlag = new CountDownLatch(1);
        CountDownLatch finishFlag = new CountDownLatch(joinMatchCnt);
        System.out.println("比赛准备开始.....");
        for (int i = 1; i <= joinMatchCnt; i++) {
            Thread t = new Thread(new Sportsman(beginMatchFlag, finishFlag, i + "号"));
            System.out.println("运动员"+i + "号已就位");
            t.start();//所有运动员都到指定位置就绪
        }
        beginMatchFlag.countDown();//裁判吹哨
        try {
            finishFlag.await();//裁判等待运动员跑完
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("比赛结束.....");
    }

    static class Sportsman implements Runnable {
        private CountDownLatch beginMatchFlag;
        private CountDownLatch finishFlag;
        private String name;

        public Sportsman(CountDownLatch beginMatchFlag, CountDownLatch finishFlag, String name) {
            this.beginMatchFlag = beginMatchFlag;
            this.finishFlag = finishFlag;
            this.name = name;
        }

        @Override
        public void run() {
            try {
                beginMatchFlag.await();//等待裁判比赛开始
                try {
                    running();
                } finally {
                    finishFlag.countDown();//运动员跑到终点,这里要放在finally中,如运动员跑步受伤,立即终止个人成绩
                }
                System.out.println("运动员" + name + "跑到终点线");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        private void running() {
            try {
                System.out.println("运动员" + name + "开始比赛");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行的结果如下

比赛准备开始.....
运动员1号已就位
运动员2号已就位
运动员3号已就位
运动员4号已就位
运动员5号已就位
运动员1号开始比赛
运动员2号开始比赛
运动员3号开始比赛
运动员4号开始比赛
运动员5号开始比赛
运动员1号跑到终点线
运动员3号跑到终点线
运动员2号跑到终点线
运动员4号跑到终点线
运动员5号跑到终点线
比赛结束.....
### 并发工具类概述 Java 提供了多种并发工具类,以帮助开发者简化多线程编程的复杂性。这些工具类位于 `java.util.concurrent` 包中,包括但不限于 `CountDownLatch`、`CyclicBarrier`、`Semaphore` 和 `Exchanger` 等。它们各自服务于不同的同步需求,例如线程间的协作、资源访问控制等。 ### CountDownLatch `CountDownLatch` 是个同步辅助类,它允许个或多个线程直等待,直到其他线程执行的组操作完成。这个类初始化时会设置个计数器,每当个操作完成时,计数器就会递减,当计数器达到零时,所有等待的线程都会被释放。 ```java CountDownLatch latch = new CountDownLatch(3); // 在某个线程中 latch.countDown(); // 每次调用计数器减 // 在等待线程中 latch.await(); // 等待计数器归零 ``` ### CyclicBarrier `CyclicBarrier` 与 `CountDownLatch` 类似,但它可以被重置并重复使用。它适用于这样种场景:组线程需要互相等待对方到达个共同的屏障点后才能继续执行。 ```java CyclicBarrier barrier = new CyclicBarrier(3, () -> { // 所有参与者都到达屏障后的动作 }); // 每个线程中 barrier.await(); ``` ### Semaphore `Semaphore` 控制着对组资源的访问。它通过维护组许可来限制同时访问的线程数量。如果有必要,线程可以尝试获取许可,并且在无法获取时会被阻塞或者失败。 ```java Semaphore semaphore = new Semaphore(5); // 允许最多5个线程同时访问 // 获取许可 semaphore.acquire(); // 释放许可 semaphore.release(); ``` ### Exchanger `Exchanger` 提供了个同步点,在这个点上两个线程可以交换数据。这对于某些特定的算法实现非常有用,比如生产者-消费者模式中的双向通信。 ```java Exchanger<String> exchanger = new Exchanger<>(); // 线程A String dataA = "Data from Thread A"; exchanger.exchange(dataA); // 线程B String dataB = "Data from Thread B"; exchanger.exchange(dataB); ``` ### 相关问题 1. 如何利用 `CountDownLatch` 实现线程间的同步等待? 2. `CyclicBarrier` 和 `CountDownLatch` 在功能上有何异同? 3. `Semaphore` 是如何控制资源访问的?它有哪些典型应用场景? 4. `Exchanger` 的工作原理是什么?它适合什么样的并发场景? 5. 并发工具类在实际开发中如何选择和使用?各自的优缺点是什么? 这些问题可以帮助进步理解和掌握 Java 并发工具类的应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值