这三个类是Java中常用的并发工具类,它们都可以用来控制多个线程的同步。

CountDownLatch

CountDownLatch是一个同步工具类,可以用于控制一个或多个线程等待多个线程完成操作,然后再执行。CountDownLatch内部使用一个计数器(初始化需要指定计数器的值)实现,在计数器值到达0之前,await()方法会阻塞线程;而每个线程完成操作后,都会调用countDown()方法,将计数器值减1。

代码示例:

public class CountDownLatchDemo {
    private static final int THREAD_COUNT = 5;
    public static void main(String[] args) {
        final CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT);
        for (int i = 0; i < THREAD_COUNT; i++) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + " 执行任务……");
                        Thread.sleep(1000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        countDownLatch.countDown();
                    }
                }
            }, "Thread-" + i);
            t.start();
        }
        try {
            System.out.println("等待 " + THREAD_COUNT + " 个线程完成任务……");
            countDownLatch.await();
            System.out.println("所有线程任务执行完成!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

CyclicBarrier

CyclicBarrier也是一个同步工具类,它可以实现多个线程相互等待,直到所有线程都到达某一同步点,然后再继续执行。CyclicBarrier内部同样使用计数器实现,不同的是计数器可以重复使用,可以通过reset()方法重置计数器。

CyclicBarrier有一个额外的任务,即在所有线程到达同步点后,执行一个“barrier action”(一个Runnable),该任务会在所有线程继续执行之前执行。

代码示例:

public class CyclicBarrierDemo {
    private static final int THREAD_COUNT = 5;
    public static void main(String[] args) {
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(THREAD_COUNT, new Runnable() {
            @Override
            public void run() {
                System.out.println("所有线程到达同步点,开始执行 barrier action 任务……");
            }
        });
        for (int i = 0; i < THREAD_COUNT; i++) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + " 执行任务……");
                        cyclicBarrier.await();
                        System.out.println(Thread.currentThread().getName() + " 继续执行任务……");
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }, "Thread-" + i);
            t.start();
        }
    }
}

Semaphore

Semaphore是一个计数信号量,可以控制对某一共享资源的访问线程数,避免多个线程同时访问该共享资源导致的线程安全问题。Semaphore常用于对有限资源的访问,如数据库连接池、线程池等。

Semaphore内部同样使用计数器实现,初始化Semaphore需要指定初始计数值,每当有一个线程访问该共享资源时,计数器会减1;当计数器值为0时,再有线程访问该共享资源时,线程会被阻塞,直到有线程释放资源,计数器值增加。

代码示例:

public class SemaphoreDemo {
    private static final int THREAD_COUNT = 10;
    private static final int SEM_COUNT = 3;
    private static final Semaphore semaphore = new Semaphore(SEM_COUNT);
    public static void main(String[] args) {
        for (int i = 0; i < THREAD_COUNT; i++) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName() + " 获得许可证,开始执行任务……");
                        Thread.sleep(1000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        System.out.println(Thread.currentThread().getName() + " 释放许可证,结束任务。");
                        semaphore.release();
                    }
                }
            }, "Thread-" + i);
            t.start();
        }
    }
}