Java并发工具箱:CountDownLatch、CyclicBarrier、Semaphore、Exchanger的神秘力量!

引言

在Java并发编程的世界里,有这样四位神秘的守护者,它们分别是CountDownLatchCyclicBarrierSemaphoreExchanger。它们各自拥有独特的魔法,帮助开发者解决各种并发问题。今天,就让我们一起揭开它们的神秘面纱,深入了解它们的运行原理、应用场景以及源码分析。

2024最全大厂面试题无需C币点我下载或者在网页打开全套面试题已打包

AI绘画关于SD,MJ,GPT,SDXL,Comfyui百科全书

夸张风格的标题

《Java并发工具箱:揭秘CountDownLatch、CyclicBarrier、Semaphore、Exchanger的神秘力量!》

CountDownLatch:倒计时的魔法

CountDownLatch是一个同步辅助类,它允许一个或多个线程等待直到在其他线程中执行的一组操作完成。它就像一个倒计时器,等待计数到达零,然后释放所有等待的线程。

运行原理

CountDownLatch内部维护了一个计数器,这个计数器的初始值由构造函数指定。每当一个线程调用countDown()方法时,计数器的值就会减一。当计数器的值减到零时,所有等待的线程都会被唤醒。

应用场景

CountDownLatch常用于以下场景:

  • 多线程等待一组操作完成:例如,多个线程在等待一组数据库操作完成后再继续执行。
  • 主线程等待多个子线程完成:在主程序中等待所有子线程执行完毕。

源码分析

public class CountDownLatch {
    private final Sync sync;

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    public void countDown() {
        sync.releaseShared(1);
    }

    // 其他方法...
}

在上述代码中,CountDownLatch类的构造函数接受一个计数器的初始值。await()方法用于等待计数器减到零,而countDown()方法用于减少计数器的值。

CyclicBarrier:循环栅栏的魔力

CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点。它就像一个循环的栅栏,线程们可以重复地等待和通过。

运行原理

CyclicBarrier内部维护了一个计数器和一个栅栏操作。当线程调用await()方法时,计数器的值会增加。当计数器的值达到构造函数中指定的值时,所有等待的线程会被唤醒,并且可以执行栅栏操作。之后,计数器会重置,等待的线程可以再次等待。

应用场景

CyclicBarrier常用于以下场景:

  • 多线程并行计算:在并行计算中,多个线程可以同时执行计算,然后在计算完成后使用CyclicBarrier等待其他线程完成。
  • 多阶段任务处理:在处理多阶段任务时,每个阶段完成后,线程可以使用CyclicBarrier等待其他线程完成当前阶段。

源码分析

public class CyclicBarrier {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition trip = lock.newCondition();
    private final int parties;
    private final Runnable barrierCommand;
    private int count;

    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

    public int await() throws InterruptedException, BrokenBarrierException {
        lock.lock();
        try {
            int index = --count;
            if (index == 0) {  // tripped
                try {
                    barrierCommand.run();
                } finally {
                    onReset();
                }
                trip.signalAll();
                return 0;
            }

            for (;;) { // loop until tripped, broken, interrupted, or timed out
                try {
                    trip.await();
                } catch (InterruptedException ie) {
                    breakBarrier();
                    throw ie;
                } catch (BrokenBarrierException e) {
                    breakBarrier();
                    throw e;
                }
            }
        } finally {
            lock.unlock();
        }
        return index;
    }

    // 其他方法...
}

在上述代码中,CyclicBarrier类的构造函数接受一个线程数和一个可选的栅栏操作。await()方法用于等待其他线程到达栅栏点。

Semaphore:信号量的奥秘

Semaphore是一个计数信号量,它控制同时访问某个特定资源的线程数量。它就像一个守门员,控制着资源的访问权限。

运行原理

Semaphore内部维护了一个计数器和一个等待队列。当线程调用acquire()方法时,如果计数器的值大于零,计数器的值会减一,线程可以继续执行。如果计数器的值为零,线程会被放入等待队列中。当线程调用release()方法时,计数器的值会增加,如果有线程在等待队列中,它们会被唤醒。

应用场景

Semaphore常用于以下场景:

  • 限流控制:控制对某个资源的并发访问数量。
  • 资源池管理:管理一组可复用的资源,如数据库连接。

源码分析

public class Semaphore {
    private final Sync sync;

    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    public void release() {
        sync.releaseShared(1);
    }

    // 其他方法...
}

在上述代码中,Semaphore类的构造函数接受一个许可数。acquire()方法用于获取许可,而release()方法用于释放许可。

Exchanger:线程间交换的魔法

Exchanger是一个用于两个线程之间交换数据的同步点。它就像一个交换站,允许两个线程在某个点交换数据。

运行原理

Exchanger内部维护了一个队列,用于存储等待交换的线程。当一个线程调用exchange()方法时,它会将数据放入队列中,并等待另一个线程到达。当另一个线程到达并调用exchange()方法时,两个线程的数据会被交换,并且两个线程都会被唤醒。

应用场景

Exchanger常用于以下场景:

  • 生产者-消费者模式:生产者和消费者在交换点交换数据。
  • 任务协作:两个线程协作完成任务,需要在某个点交换数据。

源码分析

public class Exchanger<V> {
    private final Participant participant;

    public Exchanger() {
        participant = new Participant();
    }

    public V exchange(V x) throws InterruptedException {
        return exchange(x, false, 0L);
    }

    // 其他方法...
}

在上述代码中,Exchanger类的构造函数不接受任何参数。exchange()方法用于交换数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值