这三个类是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();
}
}
}