作者jerrychen26 (水泽)
看板java
标题synchronized map的value
时间Fri Dec 17 08:57:44 2021
大家好,想请教各位前辈一个问题
今天我有一个map
Map<String, List<Integer>> map = new HashMap<>();
有一个function void safeAdd(String key, Integer value),
这个safeAdd方法要做的事情是 map.get(key).add(value) ,这边先不用考虑list 是null
请问要如何做才能达到有效率而且是执行绪安全,以下是我的想法
1. 如果是synchronized safeAdd()这样虽然安全,但是没效率,因为就算不同key 也会要等别的key 完成才能进入
2. 同上,用ConcurrentHashMap一样有这个问题
3. 在safeAdd 里面 先 list A = map.get(key) ,再用synchronized (A) { A.add(value) } ,这是我觉得比较好的作法,但是IntelliJ给我警告说synchronization on local variable,但是get 出来的应该是物件的参考,这样会有问题吗
4. 同上,在方法里面改用 synchronized (map.get(key)) {map.get(key).add(value)}
5. 不考虑用BlockingQueue 或 Vector,因为在safeAdd 里面会有其他对list 的操作,例如用size() 去控制list的长度,我希望这个safeAdd被使用的时候同一时间只有单一执行绪对一个key 里面的list 做操作。
我目前是使用4,我有测试过而且看起来是没问题,但是还是怕有什麽意外因此上来发问,再麻烦各位帮我解答,谢谢。
-----
Sent from JPTT on my iPhone
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 112.104.153.116 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/java/M.1639702666.A.CD7.html
1F:推 jej: 你的Map放在全域变数 要thread safe就有困难 12/17 09:55
2F:→ jej: 如果不能放在block里面 一定要放全域 12/17 09:56
3F:→ jej: 可以考虑用concurrent package下的lock 12/17 09:56
4F:→ jej: 或是使用 synchronized锁定这个Map 12/17 09:56
5F:→ jej: 但如果你有效能考虑 还是建议你重构 看看能不能用singleton 12/17 09:56
6F:→ jej: 把map重构在block里 12/17 09:56
7F:→ jerrychen26: 感谢回答,不过我的问题点比较在於当用synchronized( 12/17 10:05
8F:→ jerrychen26: map.get(key)) 的block期间,可以保证被get出来的这 12/17 10:05
9F:→ jerrychen26: 个list 能达成执行绪安全吗? 12/17 10:05
10F:推 jej: 你这样是锁的东西是什麽就未知了 而且也不一定是单一物件 12/17 11:12
11F:→ jej: 多执行绪还是gg吧 所以才说要不要锁map 12/17 11:12
12F:→ ssccg: ConcurrentHashMap.compute 12/17 13:00
13F:→ ssccg: (key, (k, list) -> { list.add(value); return list }); 12/17 13:02
14F:→ ssccg: 如果需要考虑list为空,就再加个检查和new 12/17 13:03
15F:→ ssccg: 不过compute只会挡update类型的作业,你要达到类似DB交易 12/17 13:16
16F:→ ssccg: (update中也block其他get)的话,就是get也改用compute 12/17 13:16
18F:→ ssccg: 你的3 4作法其实效果一样,IntelliJ的警告只是个提醒,真正 12/17 14:44
19F:→ ssccg: 的问题在於你synchonized list的期间,如果别的thread做了 12/17 14:45
20F:→ ssccg: Map.put(key, ...),你的list是安全的,但是map.get(key)已 12/17 14:46
21F:→ ssccg: 不再是你的list而是别的东西,所以一楼才建议锁map 12/17 14:47
22F:→ ssccg: 都用compute可以解决这问题 12/17 14:49
23F:→ ssccg: 更正,4的作法有个更糟的点是两个map.get(key)间还有空窗, 12/17 14:54
24F:→ ssccg: 这中间map.put(key,...)的话,呼叫add的list跟上锁的不同 12/17 14:55
25F:→ jerrychen26: 理解了,感谢解答 12/17 15:43
26F:→ darkk6: 做法跟你的 map/list 操作有关,看你是否预期他们会被改变 12/22 01:37
27F:→ darkk6: 会/不会,都有不同适合的写法 12/22 01:37
28F:→ flowwinds: 把key当mutex? 01/08 21:46