1 等待多线程完成的 CountDownLatch
CountDownLatch 允许一个或多个线程等待其他线程完成操作
private static CountDownLatch countDownLatch = new CountDownLatch(2);
private static void countDownLatch() throws InterruptedException {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + ":start");
countDownLatch.countDown();
}, "t1").start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + ":start");
countDownLatch.countDown();
}, "t2").start();
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + ":end");
}
2 同步屏障 CyclicBarrier
让一组线程达到一个屏障(同步点)时被阻塞
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
private static void cyclicBarrier() throws Exception {
new Thread(() -> {
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":start");
}, "t1").start();
new Thread(() -> {
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":start");
}, "t2").start();
// 执行到这里之后,各个线程才会开始执行
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + ":end");
}
还有更高级的构造函数 public CyclicBarrier(int parties, Runnable barrierAction),用来当线程达到屏障时,优先执行 barrierAction
public class BankWaterService implements Runnable {
private final static int COUNT = 4;
private int result = 0;
private CyclicBarrier c = new CyclicBarrier(COUNT, this);
private static ExecutorService executor = Executors.newFixedThreadPool(COUNT);
private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
private int getResult() {
return this.result;
}
private void count() {
for (int i = 0; i < COUNT; i++) {
int finalI = i;
executor.execute(() -> {
// 计算流水数据
map.put(Thread.currentThread().getName(), finalI + 1);
// 插入一个屏障
try {
c.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "end");
});
}
System.out.println("count end");
}
@Override
public void run() {
for (Map.Entry<String, Integer> stringIntegerEntry : map.entrySet()) {
result += stringIntegerEntry.getValue();
}
System.out.println("方法结束");
}
public static void main(String[] args) {
BankWaterService bankWaterService = new BankWaterService();
bankWaterService.count();
SleepUtils.second(10);
System.out.println(bankWaterService.getResult());
executor.shutdown();
System.out.println("主线程结束");
}
}
CountDownLatch 和 CyclicBarrier 的区别
- CyclicBarrier 可以使用 reset() 方法重置计数器
- CyclicBarrier 提供 getNumberWaiting() 方法获得当前阻塞的线程数量
- CyclicBarrier 提供 isBroken() 方法来了解阻塞的线程是否被中断了
3 控制并发线程数的 Semaphore
用来控制同时访问特定资源的线程数量
可以用作流量控制
private static final int THREAD_COUNT = 30;
private static ExecutorService pool = Executors.newFixedThreadPool(THREAD_COUNT);
private static Semaphore semaphore = new Semaphore(10);
private static void semaphore() throws Exception {
for (int i = 0; i < THREAD_COUNT; i++) {
pool.execute(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + ":start");
SleepUtils.second(2);
semaphore.release();
System.out.println(Thread.currentThread().getName() + ":end");
} catch (Exception e) {
e.printStackTrace();
}
});
}
pool.shutdown();
System.out.println(Thread.currentThread().getName() + ":end");
}
- 常用方法
-
- accquire()
-
- 阻塞获取许可证
- tryAccquire()
-
- 非阻塞获取许可证,没有就返回 false
- release()
-
- 释放许可证资源
- availablePermits()
-
- 返回当前可用许可证数
- getQueueLength()
-
- 获取目前正在等待获取许可证的线程数
- reducePermits(int reduction)
-
- 减少reduction个许可证
4 线程间交换数据的 Exchanger
是一个用于线程间协作的工具类,用于线程间数据交换
会提供一个同步点,两个线程在这个同步点进行数据交换
private static final Exchanger<String> exchanger = new Exchanger<>();
private static ExecutorService pool2 = Executors.newFixedThreadPool(2);
private static void exchanger() throws Exception {
pool2.execute(() -> {
try {
String a = "流水A";
String b = exchanger.exchange(a);
System.out.println("A:" + a + "\tB:" + b + "\tA和B数据是否一致:" + b.equals(a));
} catch (InterruptedException e) {
e.printStackTrace();
}
});
pool2.execute(() -> {
try {
String b = "流水B";
SleepUtils.second(10);
String a = exchanger.exchange(b);
System.out.println("A:" + a + "\tB:" + b + "\tA和B数据是否一致:" + b.equals(a));
} catch (InterruptedException e) {
e.printStackTrace();
}
});
pool2.shutdown();
}