19 | CountDownLatch和CyclicBarrier:如何让多线程步调一致?
该思维导图由 AI 生成,仅供参考
利用并行优化对账系统
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了如何利用CountDownLatch和CyclicBarrier来实现多线程的步调一致,从而优化对账系统的性能。文章首先描述了对账系统的处理逻辑和代码实现,并指出了查询订单和派送单的操作是性能瓶颈。接着,文章提出了利用多线程并行处理查询操作来优化性能,并给出了相应的代码示例。然后,介绍了如何使用CountDownLatch来实现线程等待,避免重复创建线程,进一步优化性能。最后,提出了进一步优化性能的思路,通过使用双队列和同步执行来实现完全的并行处理。总的来说,本文通过具体的代码示例和图示,生动地展示了如何利用CountDownLatch和CyclicBarrier来优化多线程的步调一致,对于需要优化多线程性能的读者具有一定的参考价值。文章还介绍了CyclicBarrier和CountDownLatch的区别和用法,以及CyclicBarrier的回调函数和线程池的使用。文章内容丰富,对于想要深入了解多线程优化的读者有很大帮助。
《Java 并发编程实战》,新⼈⾸单¥59
全部留言(155)
- 最新
- 精选
- 张申傲我觉得老师的问题其实是两个: 1.为啥要用线程池,而不是在回调函数中直接调用? 2.线程池为啥使用单线程的? 我的考虑: 1.使用线程池是为了异步操作,否则回掉函数是同步调用的,也就是本次对账操作执行完才能进行下一轮的检查。 2.线程数量固定为1,防止了多线程并发导致的数据不一致,因为订单和派送单是两个队列,只有单线程去两个队列中取消息才不会出现消息不匹配的问题。
作者回复: 👍
2019-05-2313253 - J.M.Liu老师,CyclicBarrier的回调函数在哪个线程执行啊?主线程吗?比如这里的最后一段代码中,循环会在回调的时候阻塞吗? 如果是这样的话,那check函数岂不是可以直接作为回调函数了呀,并不需要线程池了啊
作者回复: 好问题,CyclicBarrier的回调函数执行在一个回合里最后执行await()的线程上,而且同步调用回调函数check(),调用完check之后,才会开始第二回合。所以check如果不另开一线程异步执行,就起不到性能优化的作用了。
2019-04-1210182 - undifined线程池大小为1是必要的,如果设置为多个,有可能会两个线程 A 和 B 同时查询,A 的订单先返回,B 的派送单先返回,造成队列中的数据不匹配;所以1个线程实现生产数据串行执行,保证数据安全 如果用Future 的话可以更方便一些: CompletableFuture<List> pOrderFuture = CompletableFuture.supplyAsync(this::getPOrders); CompletableFuture<List> dOrderFuture = CompletableFuture.supplyAsync(this::getDOrders); pOrderFuture.thenCombine(dOrderFuture, this::check) .thenAccept(this::save); 老师这样理解对吗,谢谢老师
作者回复: 对,👍👍👍
2019-04-11580 - 空知老师,关于CyclicBarrier回调函数,请教下 自己写了个 CyclicBarrier的例子,回调函数总是在计数器归0时候执行,但是线程T1 T2要等回调函数执行结束之后才会再次执行...看了下CyclicBarrier 的源码,当内部计数器 index == 0时候, final Runnable command = barrierCommand; if (command != null) command.run(); 没有开启子线程吧.也就是说 对账还是同步执行的,结束之后才是下一次的查询
作者回复: 所以才需要线程池来异步执行回调函数,你一不小心把答案找到了😂
2019-04-11767 - 曾轼麟老师推荐您使用ThreadPoolExecutor去实现线程池,并且实现里面的RejectedExecutionHandler和ThreadFactory,这样可以方便当调用订单查询和派送单查询的时候出现full gc的时候 dump文件 可以快速定位出现问题的线程是哪个业务线程,如果是CountDownLatch,建议设置超时时间,避免由于业务死锁没有调用countDown()导致现线程睡死的情况
作者回复: 好建议,所有的阻塞操作,都需要设置超时时间,这是个很好的习惯。
2019-04-13465 - 波波思考题中,如果生产者比较快,消费者比较慢,生产者通知的时候,消费者还在对账,这个时候会怎么处理?会不会导致消费者错失通知,导致队列满了,但是消费者却没有收到通知。
作者回复: 有这种可能,还能oom
2019-04-11728 - nanquanmama最后的那个例子,业务逻辑的部分已经变得很不直观,并发控制的逻辑掩盖住了业务逻辑。请问一下老师,实际项目开发中,并发控制逻辑如何做,才能和业务逻辑分离出来?
作者回复: 放到不同的类里,这方面传统的面向对象可以解决,lambda也能解决,这个模块的最后几章能解决你说的这个问题,但是更复杂的场景还得自己设计
2019-04-1119 - ... ...追问:如果线程池是单线程的话。那假如生产者速度快运check函数执行时间。那是不是就会出现堵塞情况了。久而久之,是不是会出现队列内存溢出
作者回复: 会
2019-04-12317 - Adam如果生产者比较快,消费者check还没对账完 会不会照成 队列越来越多 最后内存溢出了 ,有没有什么好的方案解决呢?
作者回复: 方案上基本都是限流
2019-06-1414 - 忍者无敌1995有,如果为线程池有多个线程,则由于check()函数里面的两个remove并不是原子操作,可能导致消费错乱。假设订单队列中有P1,P2;派送队列中有D1,D2;两个线程T1,T2同时执行check,可能出现T1消费到P1,D2,T2消费到P2,D1,就是T1先执行pos.remove(0), 而后T2执行pos.remove(0);dos.remov(0);然后T1才执行dos.remove(0)的场景
作者回复: 多个线程有这个可能,所以线程池用的是单线程的
2019-05-01214