JUC三大辅助类

Java并发编程:CountDownLatch、CyclicBarrier与Semaphore实战解析

java.util.concurrent包为我们提供了三大辅助类,帮助我们在某些场景下快速编写并发代码。

  1. CountDownLatch

CountDownLatch(int count)
Constructs a CountDownLatch initialized with the given count.
构造一个用给定计数初始化的CountDownLatch。

CountDownLatch类可以设置一个计数器,然后通过countDown方法来进行减一的操作,使用await方法等待计数器不大于0,然后继续执行await方法之后的语句。
CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞。其他线程调用countDown方法会将计数器减一(调用countDown方法的线程不会阻塞)。
当计数器的值变为0时,因await方法而阻塞的线程会被唤醒,继续执行。

案例演示:

import java.util.concurrent.CountDownLatch;

// 演示CountDownLatch
public class CountDownLatchDemo {
    // 6个同学陆续离开教室后,班长锁门
    public static void main(String[] args) throws InterruptedException {
        // 创建CountDownLatch对象,设置初始值
        CountDownLatch countDownLatch = new CountDownLatch(6);
        // 6个同学陆续离开教室
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "号同学离开了教室");
                // 计数-1
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }
        // 等待
        countDownLatch.await();
        System.out.println(Thread.currentThread().getName() + "班长锁门");
    }
}

执行结果:
执行结果
2. CyclicBarrier

CyclicBarrier(int parties)
Creates a new CyclicBarrier that will trip when the given number of parties (threads) are waiting upon it, and does not perform a predefined action when the barrier is tripped.
创建一个新的CyclicBarrier,当给定数量的参与方(线程)在等待它时,它将触发,并且在触发barrier时不执行预定义的操作。
CyclicBarrier(int parties, Runnable barrierAction)
Creates a new CyclicBarrier that will trip when the given number of parties (threads) are waiting upon it, and which will execute the given barrier action when the barrier is tripped, performed by the last thread entering the barrier.
创建一个新的CyclicBarrier,当给定数量的参与方(线程)在等待它时,它将被绊倒;当barrier被绊倒时,它将执行给定的barrier动作,由最后一个进入barrier的线程执行。

CyclicBarrier允许一组线程互相等待,直到到达某个公共屏障点。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时CyclicBarrier很有用。因为该barrier在释放等待线程后可以重用,所以称它为循环栅栏。
CyclicBarrier的构造方法第一个参数是目标障碍数,每次执行CyclicBarrier一次障碍数会加一,如果达到了目标障碍数,才会执行cyclicBarrier.await()之后的语句;可以将CyclicBarrier理解为加一操作。

案例演示:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

// 演示CyclicBarrier
public class CyclicBarrierDemo {
    // 集齐7颗龙珠就可以召唤神龙
    private static final int NUMBER = 7;
    public static void main(String[] args) {
        // 创建CyclicBarrier对象
        CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
            System.out.println("集齐7颗龙珠就可以召唤神龙");
        });
        // 集齐7颗龙珠的过程
        for (int i = 1; i <= NUMBER ; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "星龙珠");
                // 等待
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}

执行结果:
执行结果

  1. Semaphore

Semaphore(int permits)
Creates a Semaphore with the given number of permits and nonfair fairness setting.
使用给定的许可数量和非公平性设置创建一个信号量。
Semaphore(int permits, boolean fair)
Creates a Semaphore with the given number of permits and the given fairness setting.
使用给定的许可数量和公平性设置创建一个信号量。

一个计数信号量,从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个acquire方法,然后再获取该许可。每个acquire方法添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,semaphore只对可用许可的号码进行计数,并采取相应的行动。
Semaphore通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。

案例演示:

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

// 演示Semaphore
public class SemaphoreDemo {
    // 6辆汽车,停3个停车位
    public static void main(String[] args) {
        // 创建Semaphore,设置许可数量
        Semaphore semaphore = new Semaphore(3);
        // 模拟6辆汽车
        for (int i = 1; i <= 6 ; i++) {
            new Thread(() -> {
                try {
                    // 抢占
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " 抢到了车位");
                    // 设置随机停车时间
                    TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                    System.out.println(Thread.currentThread().getName() + " -----离开了车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 释放
                    semaphore.release();
                }
            }, String.valueOf(i)).start();
        }
    }
}

执行结果:
执行结果

### Java JUC 并发包中的同步工具 #### CountDownLatch 的使用方法 `CountDownLatch` 是一种同步辅助,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。此计数器无法重新设置;也就是说,当计数值达到零时,不可以通过任何方式将其重置为更的值[^2]。 ```java import java.util.concurrent.CountDownLatch; public class Test { public static void main(String[] args) throws InterruptedException { int threadCount = 5; final CountDownLatch countDownLatch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; ++i){ new Thread(() ->{ try { System.out.println(Thread.currentThread().getName() + " is working"); Thread.sleep(1000); // Simulate work being done. System.out.println(Thread.currentThread().getName() + " finished."); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); // Decrements the count of the latch, releasing all waiting threads if the count reaches zero. }).start(); } countDownLatch.await(); // Blocks until the count reaches zero due to invocations of the `countDown()` method from other threads. System.out.println("All tasks are completed!"); } } ``` #### CyclicBarrier 的使用方法 `CyclicBarrier` 支持一定数量的线程彼此之间互相等待,一旦达到了指定的数量,则可以继续执行后续的任务。与 `CountDownLatch` 不同的是,它可以重复利用已设定好的状态[^4]。 ```java import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; class Task implements Runnable { private CyclicBarrier cb; public Task(CyclicBarrier cb) { this.cb = cb; } @Override public void run() { try { System.out.println(Thread.currentThread().getName() + ": 已经到达障碍点,正在等待..."); cb.await(); // 所有参与者都已经抵达屏障处后要做的工作... System.out.println(Thread.currentThread().getName() + ": 继续前进!"); } catch (InterruptedException | BrokenBarrierException ex) { ex.printStackTrace(); } } } public class BarrierExample { public static void main(String[] args) { int parties = 3; CyclicBarrier barrier = new CyclicBarrier(parties); for(int i=0;i<parties;++i) new Thread(new Task(barrier)).start(); } } ``` #### Semaphore 的使用方法 信号量用于控制访问特定资源的线程数目,它维护了一个许可集合。如有必要,在许可可用前会阻塞每一个 acquire 方法,然后再获取该许可。每个 release 方法都会返回一个许可,从而可能释放一个阻塞的 acquire。 ```java import java.util.concurrent.Semaphore; public class LimitedResourceAccess { private static final int MAX_PERMITS = 3; public static void main(String[] args) { Semaphore semaphore = new Semaphore(MAX_PERMITS); for (int i = 0; i < 6; ++i) { // More requests than permits available. new Thread(() -> { try { semaphore.acquire(); // Acquire a permit before accessing resource. String name = Thread.currentThread().getName(); System.out.printf("%s acquired access.\n", name); Thread.sleep((long)(Math.random()*1000)); // Simulating time spent using resources System.out.printf("%s released access.\n", name); semaphore.release(); // Release the permit after finishing with resource. } catch (InterruptedException ie) {} }, "Thread-" + i).start(); } } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

PandaThug

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

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

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

打赏作者

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

抵扣说明:

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

余额充值