Java 多线程导致 Service 之间互相调用,有什么解耦或者优化办法吗?

2023-03-24 14:21:12 +08:00
 cencoroll

目前碰到一个需求,serviceA 向外发送数据,走完前调用 serviceB 开启一条支线程去重复持续获取操作结果,直到获取结果为止,然后更新 serviceA 的数据状态。 这样导致了 serviceA 调用 serviceB ,然后 serviceB 又要调用 serviceA ,造成了循环调用。 求问各位大佬有什么办法优化一下,另外有多线程和设计模式的书推荐一下嘛?谢谢!

2190 次点击
所在节点    Java
12 条回复
xiaohundun
2023-03-24 14:26:52 +08:00
这种为啥不用发布订阅或者基于事件的方式?
shinyruo2020
2023-03-24 14:35:01 +08:00
这不就是回调吗,serviceA 传一个 Function 给 serviceB
liudaolunhuibl
2023-03-24 14:37:39 +08:00
1 、你要解耦的话,就重新写一个 serviceC 来获取 A 的数据,serviceA 可以叫 producrService serviceC 就是 consumer Service ,A 负责发数据和写数据,C 负责读取查询,这样 A 发送完数据,调用 B ,B 调用 C 去查询数据,可以理解为读写分离
2 、重复持续获取就是轮询吧 ,轮询不是非常的优雅,因为长时间的轮训会给 CPU 造成压力,最好是按照一楼说的基于事件驱动,也就是操作结果完成之后调用 B ,可以用 MQ 或者单节点就用谷歌的 eventBUs 或者 spring event
3 、多线程和设计模式的书网上一搜一大把
yazinnnn
2023-03-24 14:51:18 +08:00
你用的啥客户端, 异步却不支持设置回调?

client
.send(xxx)
.onSuccess(result-> handle(result))
.onFailure(error->handle(error))

这种形式的代码都不支持码?
litchinn
2023-03-24 15:08:14 +08:00
事件驱动
serviceA 里发布事件,eventA.send()
serviceB 作为一个 eventA 的监听器,执行完任务后再发送 eventB
serviceA 里再包含一个 eventB 的监听器,监听到 B 事件后更新数据

eventA 和 eventB 可以是同一个事件具有不同的状态,也可以是多个事件,看你的业务进行设计

单体服务用多线程就可以了,分布式集群的话用 mq ,如 3 楼所说的方案
cencoroll
2023-03-24 15:24:49 +08:00
@liudaolunhuibl
@xiaohundun
@litchinn
非常感谢,大概找到方向了,我研究一下。

@shinyruo2020 回调不太符合需求,但也感谢解答

@yazinnnn 程序其实是操作工控设备,将参数 A 下发以后,等待执行完毕后获取结果。但是这个等待的时长不确定,而且这个结果只需要更新到数据库就行,除非程序遇到情况报错了,否则前端不太需要查看执行结果。
nothingistrue
2023-03-24 16:24:00 +08:00
如果把 serviceA 、serviceB 看成两个独立的微服务,那么这就不是互相调用,是分布式事件流,虽然看起来比较乱,但是并没有耦合,因为每个 service 都是自成一体,仅通过接口跟外部沟通的。

不过你这个还是有点耦合,需要稍微拆解一下。改成如下过程:
-> A 在队列( A 让 B 处理)当中发送一条任务
-> B 从队列收到任务后,执行,得出结果后,在另一个队列( B 返回结果给 A )上,发送处理结果
-> A 从队列收到结果后,执行后续处理(更新数据状态、向外发送等)。

注意一点:如果 A 之前还有调用者,那么 A 是无法向调用者返回最终执行结果的,因为 A 在第一个过程就必须终止同步处理,后面的全是异步的。
zhuisui
2023-03-24 17:08:17 +08:00
解耦的关键是消除业务循环依赖关系,从来都不是程序的依赖关系。
不管是程序内部的回调函数,还是程序外部的 rpc 或消息队列,或者是什么别的调用形式。
A 委托 B 做一件事,那么 A 就要负责主动接受处理结果。
几种调用方式上,提供回调明示了这个意图,其他异步方式较为隐晦。如果是 rpc ,应该 B 提供 rpc 给 A 进行委托处理和获取结果。如果是消息队列,应该由 B 声明两种工作的消息通道和内容。
总结来说,就是 B 不知道 A 。
winglight2016
2023-03-24 17:22:10 +08:00
工控设备居然用 java 操作?一般不是用串口线走 mobus 协议,只管轮询 /更新数据区这种方式吗?

想模拟这种方式的话,用 redis 充当数据区就可以了
Pony69
2023-03-24 17:51:42 +08:00
mq 或者 redis 队列
urnoob
2023-03-24 18:33:48 +08:00
AB 是
两个 jvm ,没问题啊(又不是不能用)
两个类的 instance
合二为一
抽到 C
学多线程,避免 hang 在那
学多线程知识,避免 hang 在那里
cencoroll
2023-03-25 08:21:19 +08:00
@winglight2016 这边大部分都是网口,西门子或是三菱的,直接通过 ip 地址读写数据块的信息。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/926840

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX