【Java并发】辅助类CountDownLatch、CyclicBarrier、Semaphore

目录

什么是CountDownLatch

使用CountDownLatch

方法

1. countDown()

2. await()

案例

什么是CyclicBarrier

使用CyclicBarrier

方法

1. await() 

案例

什么是Semaphore

使用Semaphore

方法

1. acquire() 

2. release() 

案例


什么是CountDownLatch

CountDownLatch 允许一个或多个线程等待一组操作在其他线程中完成。CountDownLatch 是一次性的,计数器的值只能设置一次,且一旦倒数到零,就不能被重置。

使用CountDownLatch

方法

1. countDown()
  • 作用:递减 CountDownLatch 中的计数器。

  • 使用场景:通常在线程完成其工作后调用此方法。每次调用 countDown() 方法,计数器的值就会减少一。

  • 特点

    • 如果计数器的值已经为零,则调用 countDown() 方法不会有任何效果。

    • 计数器的值只能递减,不能递增。

    • 一旦计数器的值递减到零,就不能被重置。

2. await()
  • 作用:使当前线程等待,直到 CountDownLatch 中的计数器递减到零。

  • 使用场景:通常在需要等待其他线程完成工作时使用。例如,主线程需要等待所有子线程执行完毕后再继续执行。

  • 特点

    • 如果计数器的值已经为零,则调用 await() 方法会立即返回,不会阻塞当前线程。

    • 如果计数器的值大于零,则调用 await() 方法的线程会被阻塞,直到计数器的值递减到零。

    • await() 方法可以被中断。如果当前线程在等待时被中断,则会抛出 InterruptedException 异常。

案例

public static void main(String[] args) throws InterruptedException {
    // 计数器
    CountDownLatch countDownLatch = new CountDownLatch(6);
    for (int i = 1; i <= 6; i++) {
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " Start");
            countDownLatch.countDown(); // 计数器-1
        }, String.valueOf(i)).start();
    }
    // 阻塞等待计数器归零
    countDownLatch.await();
    System.out.println(Thread.currentThread().getName() + " End");
}

本案例中,countDown() 方法用于递减计数器,而 await() 方法用于等待计数器递减到零。通过这种方式,主线程能够确保所有子线程都执行完毕后再继续执行。

什么是CyclicBarrier

CyclicBarrier允许一组线程相互等待,直到所有线程都到达一个公共屏障点(Barrier)。与 CountDownLatch 不同,CyclicBarrier 是可重用的,可以在计数器归零后重置,因此可以用于多个场景下的循环同步。

使用CyclicBarrier

方法

1. await() 
  • 作用:使当前线程在屏障点等待,直到所有线程都到达屏障点。

  • 异常

    • InterruptedException:如果当前线程在等待时被中断。在这种情况下,线程会退出等待状态,并抛出 InterruptedException

    • BrokenBarrierException:如果屏障被破坏(例如,其他线程在等待时被中断或超时)。在这种情况下,所有正在等待的线程都会抛出 BrokenBarrierException

案例

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        // CyclicBarrier(int parties, Runnable barrierAction)
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("7个线程执行完毕");
        });
        for (int i = 1; i <= 7; i++) {
            final int tempInt = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "这是第" + tempInt + "个线程");
                try {
                    cyclicBarrier.await(); // 等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

本案例中,我们创建了一个 CyclicBarrier 对象,指定了参与者数量为 7,并设置了一个屏障动作,当所有线程都到达屏障点时,会打印 "7个线程执行完毕"。然后创建了 7 个线程,每个线程在执行完任务后都会调用 cyclicBarrier.await() 方法到达屏障点等待。当所有线程都到达屏障点时,屏障动作会被执行。

什么是Semaphore

Semaphore 用于控制同时访问某个特定资源的线程数量。Semaphore 通过维护一组许可证来实现对资源的访问控制,每个许可证代表对资源的一次访问权限。

使用Semaphore

方法

1. acquire() 
  • 作用:从 Semaphore 中获取一个许可证。如果没有可用的许可证,则阻塞当前线程,直到获取到一个许可证。

  • 特点

    • 如果当前有可用的许可证,则立即获取一个,并减少可用许可证的数量。

    • 如果没有可用的许可证,则当前线程会被阻塞,直到其他线程释放许可证。

  • 异常:如果当前线程在等待许可证时被中断,则抛出 InterruptedException

2. release() 
  • 作用:释放一个许可证,将其返回给 Semaphore。这会增加可用的许可证数量,可能会唤醒正在等待许可证的线程。

  • 特点

    • 释放许可证后,Semaphore 中的可用许可证数量会增加。

    • 如果有其他线程正在等待许可证,则可能会唤醒一个或多个等待的线程。

案例

public static void main(String[] args) {
        // 创建一个Semaphore,初始许可证数量为3
        Semaphore semaphore = new Semaphore(3);

        // 创建5个线程,模拟对资源的访问
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    // 获取一个许可证
                    semaphore.acquire();
                    System.out.println("线程" + Thread.currentThread().getName() + "访问资源");
                    // 模拟资源访问时间
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 释放一个许可证
                    semaphore.release();
                }
            }, "Thread-" + i).start();
        }
    }

本案例中,Semaphore 被用于限制对某个资源的并发访问。首先创建了一个 Semaphore 对象,初始许可证数量为 3。然后创建了 5 个线程,每个线程在执行时都会尝试获取一个许可证。如果获取到许可证,则访问资源,并在访问完成后释放许可证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hrhcode

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值