比如一个场景,需要先调用几个接口,获取到调用结果之后统一处理
对于这种情况,第一的思路就是异步多线程获取接口返回结果
那么就是对于接口的调用,采用了多线程的处理方式
那么更好的解决方法就是使用了CountDownLatch
在CountDownLatch中,初始化传入一个计数器,在计数器中,进行调用多个接口,调用一次将Count减一,让主线程进行等待,等待降为0在进行唤醒执行处理
接下来的代码就是关于CountDownLatch的简单使用
// 创建2个线程的线程池
Executor executor =
Executors.newFixedThreadPool(2);
while (存在未对账订单) {
// 计数器初始化为2
CountDownLatch latch =
new CountDownLatch(2);
// 查询未对账订单
executor.execute(() -> {
pos = getPOrders();
latch.countDown();
});
// 查询派送单
executor.execute(() -> {
dos = getDOrders();
latch.countDown();
});
// 等待两个查询操作结束
latch.await();
// 执行对账操作
diff = check(pos, dos);
// 差异写入差异库
save(diff);
}
如果需要,确保多个获取的任务都完成后再放入队列中,让消费者不断的消费,
那么可以使用CyclicBarrier来实现同步问题,CylicBarrier也需要传入一个初始化数值,和一个回调函数
计数器为0的时候,会调用这个回调函数
而且CylicBarrier支持在归为0后重新再重置为初始化数值
对于上面的代码来说,就是多个查询接口多个线程,每个任务一旦完成就进行减一
// 订单队列
Vector<P> pos;
// 派送单队列
Vector<D> dos;
// 执行回调的线程池
Executor executor =
Executors.newFixedThreadPool(1);
final CyclicBarrier barrier =
new CyclicBarrier(2, () -> {
executor.execute(() -> check());
});
void check () {
P p = pos.remove(0);
D d = dos.remove(0);
// 执行对账操作
diff = check(p, d);
// 差异写入差异库
save(diff);
}
void checkAll () {
// 循环查询订单库
Thread T1 = new Thread(() -> {
while (存在未对账订单) {
// 查询订单库
pos.add(getPOrders());
// 等待
barrier.await();
}
});
T1.start();
// 循环查询运单库
Thread T2 = new Thread(() -> {
while (存在未对账订单) {
// 查询运单库
dos.add(getDOrders());
// 等待
barrier.await();
}
});
T2.start();
}
对于CountDownLatch和CylicBarrier是Java并发包两个工具类,看起来功能相似
但是CountDownLatch更像是一次使用的,一个线程等待多个线程
CylicBarrier是一组线程之间相互等待,而且可以循环利用的