Bootstrap

【JUC —— 07 CountDownLatch、CyclicBarrier和Semaphore】

CountDownLatchCyclicBarrierSemaphore是Java并发包中的三种常用同步工具,它们在多线程编程中有各自的特定用途。以下是它们的详细介绍和示例代码:

1. CountDownLatch

  • CountDownLatch是一个同步辅助类,用于使一个或多个线程等待直到其他线程中的操作执行完毕。
  • 它的核心概念是一个计数器,线程可以通过调用countDown()方法来减少计数器,
  • 当计数器到达零时,所有等待(await();)的线程会被唤醒。
 示例:主线程等待多个线程完成
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        int numberOfThreads = 3;
        CountDownLatch latch = new CountDownLatch(numberOfThreads);

        for (int i = 0; i < numberOfThreads; i++) {
            new Thread(new Worker(latch)).start();
        }

        // 等待所有工人完成任务
        latch.await();
        System.out.println("All workers have finished their tasks.");
    }

    static class Worker implements Runnable {
        private final CountDownLatch latch;

        Worker(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                // 模拟任务处理
                Thread.sleep((long) (Math.random() * 1000));
                System.out.println(Thread.currentThread().getName() + " finished its task.");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                latch.countDown();
            }
        }
    }
}

2. CyclicBarrier

  • CyclicBarrier是一个同步辅助类,它允许一组线程相互等待(await()),直到它们都到达一个共同的屏障点。
  • CountDownLatch不同的是,CyclicBarrier可以重复使用。
示例:多个线程相互等待,直到所有线程都到达屏障点
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        int numberOfThreads = 3;
        CyclicBarrier barrier = new CyclicBarrier(numberOfThreads, () -> {
            System.out.println("All parties have arrived at barrier, let's proceed.");
        });

        for (int i = 0; i < numberOfThreads; i++) {
            new Thread(new Worker(barrier)).start();
        }
    }

    static class Worker implements Runnable {
        private final CyclicBarrier barrier;

        Worker(CyclicBarrier barrier) {
            this.barrier = barrier;
        }

        @Override
        public void run() {
            try {
                // 模拟任务处理
                Thread.sleep((long) (Math.random() * 1000));
                System.out.println(Thread.currentThread().getName() + " reached the barrier.");
                barrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

3. Semaphore

  • Semaphore是一个计数信号量,用于控制对某个资源的访问。
  • 它维护了一个许可集,线程可以通过调用acquire()方法获取许可,调用release()方法释放许可。
  • 当没有许可可用时,调用acquire()的线程会被阻塞。
示例:限制对资源的并发访问
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    public static void main(String[] args) {
        int numberOfPermits = 3;
        Semaphore semaphore = new Semaphore(numberOfPermits);

        for (int i = 0; i < 10; i++) {
            new Thread(new Worker(semaphore)).start();
        }
    }

    static class Worker implements Runnable {
        private final Semaphore semaphore;

        Worker(Semaphore semaphore) {
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName() + " acquired a permit.");
                // 模拟任务处理
                Thread.sleep((long) (Math.random() * 1000));
                System.out.println(Thread.currentThread().getName() + " released a permit.");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                semaphore.release();
            }
        }
    }
}

总结

  • CountDownLatch:用于一个或多个线程等待其他线程完成操作。计数器到达零时,所有等待的线程都会被唤醒。
  • CyclicBarrier:用于一组线程相互等待,直到所有线程都到达屏障点。屏障可以重复使用。
  • Semaphore:用于控制对资源的并发访问,通过许可机制实现。线程可以获取和释放许可,当没有许可可用时,线程会被阻塞。

;