CountDownLatch 是 Java 并发包提供的一个同步工具类,用于控制多个线程之间的同步。
CountDownLatch 具有一个计数器,初始化时设置一个数值,每当一个线程完成了一定的操作,就将计数器减 1。当计数器减至 0 时,表示所有的操作都已完成,可以继续执行后续的操作。通常情况下,主线程会在 CountDownLatch 上等待,直到计数器减至 0,才会继续执行。
CountDownLatch 主要用于等待多个线程完成某个操作之后再继续执行后续操作,比如多个线程都完成了数据的准备工作后再进行数据的处理。
与 CountDownLatch 不同的是,信号量(Semaphore)是另一个 Java 并发包提供的同步工具类,它也可以用于线程之间的同步,但是与 CountDownLatch 不同,信号量可以控制同时访问某个共享资源的线程数量,从而实现对共享资源的保护。
信号量的实现方式是维护一个计数器和一个等待队列,计数器表示当前可访问共享资源的线程数,等待队列保存着正在等待访问共享资源的线程。当一个线程访问共享资源时,信号量会将计数器减 1,当计数器减至 0 时,表示当前已经没有可用的资源了,所有的线程都需要进入等待队列等待。
与 CountDownLatch 相比,信号量的应用场景更加广泛,可以用于控制同时访问共享资源的线程数量、实现线程的优先级控制等。但是,使用信号量需要更加注意对共享资源的保护,防止出现死锁、饥饿等问题。
CountDownLatch 用于等待多个线程完成任务后再继续执行主线程的任务,它的作用类似于一个计数器,主线程等待计数器变为零时再继续执行。CountDownLatch 初始化时需要指定计数器的初始值,每个线程完成任务时调用 countDown() 方法将计数器减一,主线程调用 await() 方法等待计数器变为零。
下面是一个 CountDownLatch 的例子:
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
new Thread(() -> {
System.out.println("Thread 1 is running...");
latch.countDown();
}).start();
new Thread(() -> {
System.out.println("Thread 2 is running...");
latch.countDown();
}).start();
new Thread(() -> {
System.out.println("Thread 3 is running...");
latch.countDown();
}).start();
latch.await();
System.out.println("All threads have finished running.");
}
}
Semaphore 用于控制同时访问某个资源的线程数,它的作用类似于一个信号量,线程需要先获取信号量才能继续执行,执行完后再释放信号量。Semaphore 初始化时需要指定信号量的数量,每个线程需要访问资源时调用 acquire() 方法获取一个信号量,访问完成后调用 release() 方法释放信号量。
下面是一个 Semaphore 的例子:
public class SemaphoreExample {
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(2);
new Thread(() -> {
try {
semaphore.acquire();
System.out.println("Thread 1 is running...");
Thread.sleep(1000);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
semaphore.acquire();
System.out.println("Thread 2 is running...");
Thread.sleep(1000);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
semaphore.acquire();
System.out.println("Thread 3 is running...");
Thread.sleep(1000);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
从上面的例子可以看出,CountDownLatch 用于等待多个线程完成任务后再继续执行主线程的任务,它的作用类似于一个计数器,主线程等待计数器变为零时再继续执行;而 Semaphore 用于控制同时访问某个资源的线程数,它的作用类似于一个信号量,线程需要先获取信号量才能继续执行,执行完后再释放信号量。