这种线程间通信场景如何实现?

济南大飞哥 2018-08-28 12:05:15
1、有一个ConcurrentHashMap<Integer,String>,有一个线程会不断的往里面set id、value
2、有多个线程去get(id),get不到就等待,get到就remove。
每个线程传递的id不同,set进去的id每次也是不同的,最终能一一对应上。

我想到的方案是
1、ReentrantLock,读取线程需要获取锁,然后get,get不到await释放锁。使用ReentrantLock的condition实现线程间通信。
2、set方法每次set后signalall()读线程。
典型的一写多读,并发变成串行的方法,已经验证可行。

观察我的场景,get的时候传递的id能确定每次是不同的,set进去的id每次也是不同的,最终能一一对应上。
所以我想改成
1、get 并行执行,如果get不到等待。
2、set方法,set完毕能通知/或者唤醒 get线程。
也即是说方案一的性能我认为有提高的空间,get的时候,每个人get自己的,完全不应该串行,而且使用ReentrantLock+condition,读与写之间也得争用锁,性能应该有损失。

我想到用一个list<object>来存储锁,每个get线程自己new一个对象,存入list中, 然后锁住这个对象,get不到,就wait;set方法每次set完,遍历list,依次锁住后,notifyall。

这个方案还没有验证,我觉得主要的问题是使用了object的wait、notifyall,不够优雅,二是比起方案一多了一个list,增加了复杂性。不知道还有没有其他方案。
...全文
295 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
济南大飞哥 2018-09-08
  • 打赏
  • 举报
回复
引用 3 楼 yql1986 的回复:
ConcurrentHashMap 本身就是线程安全的,实在搞不明白你为啥还要加锁? 一个线程往 ConcurrentHashMap 中 set id ,有多个线程remove id .我觉得你可以这样设计,使用异步事件通知 是可以做到。 set 线程再set 完之后,可以触发一个事件;remove线程再执行remove id时,如果remove失败,可以将失败的id保存到线程变量之中,当remove线程监控到set线程触发的事件之后,根据传递过来的事件对象中的id来匹配线程变量中保存的id 如果匹配到了就执行remove操作,如果没有匹配到也可以保存到线程变量中,不过这个id要跟直接传递给remove 线程的id区别开来。

set线程和remove线程之间通过事件进行通信。


你这种场景,实在没有必要 get(id),get不到就等待,get到就remove 。 set线程尽管set id. 多个线程可以同时去remove。如果remove失败,没有必要get等待到直至map中有id ,可以使用双向队列来解决。remove线程每次都从双向队列的头部取id 执行get(id) remove操作,如果失败则将id放到队列的尾部;接下来执行传递给线程的id,如果失败也放到队列的尾部,如此循环下去。

我是想get不到就等到,每次set时不知道是谁的,set后最好能通知到对应的get方。

基本有思路了,就是使用事件通知机制。
济南大飞哥 2018-08-29
  • 打赏
  • 举报
回复
引用 1 楼 verejava 的回复:
并发编程 之 锁 Lock 取款机例子

http://www.verejava.com/?id=17236703718463

verejava 2018-08-29
  • 打赏
  • 举报
回复
并发编程 之 锁 Lock 取款机例子

http://www.verejava.com/?id=17236703718463
yql1986 2018-08-29
  • 打赏
  • 举报
回复
ConcurrentHashMap 本身就是线程安全的,实在搞不明白你为啥还要加锁? 一个线程往 ConcurrentHashMap 中 set id ,有多个线程remove id .我觉得你可以这样设计,使用异步事件通知 是可以做到。 set 线程再set 完之后,可以触发一个事件;remove线程再执行remove id时,如果remove失败,可以将失败的id保存到线程变量之中,当remove线程监控到set线程触发的事件之后,根据传递过来的事件对象中的id来匹配线程变量中保存的id 如果匹配到了就执行remove操作,如果没有匹配到也可以保存到线程变量中,不过这个id要跟直接传递给remove 线程的id区别开来。

set线程和remove线程之间通过事件进行通信。


你这种场景,实在没有必要 get(id),get不到就等待,get到就remove 。 set线程尽管set id. 多个线程可以同时去remove。如果remove失败,没有必要get等待到直至map中有id ,可以使用双向队列来解决。remove线程每次都从双向队列的头部取id 执行get(id) remove操作,如果失败则将id放到队列的尾部;接下来执行传递给线程的id,如果失败也放到队列的尾部,如此循环下去。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧