可以使用CountDownLatch 和 CyclicBarrier
// 订单队列 Vector<P> pos; // 派送单队列 Vector<D> dos; // 执行回调的线程池 Excutor excutor = Excutors.newFixedThreadPool(1); final CyclicBarrier barrier = new CyclicBarrier(2,()->{ executor.executo(()->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(()->{ // 查询运单库 dos.add(getDOrders()); // 等待 barrier.await(); }); T2.start(); }
总结:
CountDownLatch 和 CyclicBarrier 是 Java 并发包提供的两个非常易用的线程同步工具类,这两个工具类用法的区别在这里还是有必要再强调一下:CountDownLatch 主要用来解决一个线程等待多个线程的场景,可以类比旅游团团长要等待所有的游客到齐才能去下一个景点;而 CyclicBarrier 是一组线程之间互相等待,更像是几个驴友之间不离不弃。除此之外 CountDownLatch 的计数器是不能循环利用的,也就是说一旦计数器减到 0,再有线程调用 await(),该线程会直接通过。但 CyclicBarrier 的计数器是可以循环利用的,而且具备自动重置的功能,一旦计数器减到 0 会自动重置到你设置的初始值。除此之外,CyclicBarrier 还可以设置回调函数,可以说是功能丰富。本章的示例代码中有两处用到了线程池,你现在只需要大概了解即可,因为线程池相关的知识咱们专栏后面还会有详细介绍。另外,线程池提供了 Future 特性,我们也可以利用 Future 特性来实现线程之间的等待,这个后面我们也会详细介绍。