并发编程有一些工具类有CountDownLatch、CyclicBarrier、Semaphore和Exchanger等。
CountDownLatch
- CountDownLatch允许一个或多个线程等待其他线程完成操作。它内部维护一个计数器,每次调用countDown()方法时计数器减一,当计数器到达零时,等待的线程被唤醒继续执行。
- 它适用于确保某个活动直到其他某些活动都完成后再继续进行。例如,在并行计算中,主线程需要等待所有工作线程都完成计算后才能继续处理结果。
使用场景
public static void main(String[] args) throws InterruptedException {
// 创建一个计数器,计数器的初始值为3
CountDownLatch latch = new CountDownLatch(3);
// 创建三个工作线程
for (int i = 0; i < 3; i++) {
final int threadId = i;
new Thread(()->{
try {
System.out.println("线程"+threadId+"正在准备中。。。");
Thread.sleep((long) (Math.random()*1000));
System.out.println("线程"+threadId+"准备完毕,等待其他线程...");
latch.countDown();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
}
// 主线程等待其他三个线程完成准备工作
latch.await();
System.out.println("所有线程准备完毕,主线程继续执行...");
}
CyclicBarrier
- CyclicBarrier是一个可重用的屏障,它允许一组线程互相等待,直到所有线程都到达某个屏障点才继续执行。
- 它适用于并行迭代计算,每个线程处理一部分数据,当所有线程都完成处理后,它们在屏障点汇合,然后开始下一轮迭代。
- CyclicBarrier可以在所有线程到达屏障点后,执行一个预定义的Runnable命令。
使用场景
public static void main(String[] args) {
// 创建一个CyclicBarrier实例,当到达屏障的线程数量为3时,执行一个预先定义的任务
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程都到达屏障点,开始执行预定义任务...");
});
// 创建三个工作线程
for (int i = 0; i < 3; i++) {
final int threadId = i;
new Thread(() -> {
try {
System.out.println("线程" + threadId + "正在执行任务...");
Thread.sleep((long) (Math.random() * 1000)); // 模拟线程执行任务
System.out.println("线程" + threadId + "到达屏障点,等待其他线程...");
barrier.await(); // 等待其他线程到达屏障点
System.out.println("线程" + threadId + "继续执行...");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
执行顺序是当所有线程都到达屏障点的时候,限制性预定义任务,然后再继续执行。
Semaphore
- Semaphore是一个计数信号量,它维护了一组许可(permit),线程可以通过acquire()获取许可,通过release()释放许可。
- 如果没有可用的许可,acquire()将阻塞直到有许可被释放。
- 它适用于限制对某个特定资源的并发访问数量,例如,限制对数据库连接池的连接数量。
使用场景
public static void main(String[] args) {
// 创建一个Semaphore实例,表示可用的数据库连接数量
Semaphore semaphore = new Semaphore(3);
// 创建多个线程模拟数据库连接请求
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
// 获取数据库连接
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " 获取到数据库连接,开始处理请求...");
// 模拟数据库操作
Thread.sleep((long) (Math.random() * 1000));
// 释放数据库连接
System.out.println(Thread.currentThread().getName() + " 处理请求完毕,释放数据库连接");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
Exchanger
- Exchanger是一个用于线程间交换数据的同步点。它允许在并发线程中同步交换数据。
- 当两个线程都到达交换点时,它们交换数据结构,然后继续执行。
- 它适用于遗传算法、流水线设计等场景,其中数据需要在两个线程间来回传递。
使用场景
public static void main(String[] args) {
// 创建一个Exchanger实例
Exchanger<String> exchanger = new Exchanger<>();
// 创建两个线程,模拟数据交换
new Thread(() -> {
String data1 = "数据A";
try {
System.out.println(Thread.currentThread().getName() + " 正在交换数据: " + data1);
String data2 = exchanger.exchange(data1);
System.out.println(Thread.currentThread().Name() + " 收到交换后的数据: " + data2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
String data1 = "数据B";
try {
System.out.println(Thread.currentThread().getName() + " 正在交换数据: " + data1);
String data2 = exchanger.exchange(data1);
System.out.println(Thread.currentThread().getName() + " 收到交换后的数据: " + data2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}