多线程Map并发读后修改
两个线程同时操作一个全局map,如何保证值不被覆盖?
public static Map<Integer, String> DATA_MAP = new ConcurrentHashMap<>(16);
DATA_MAP.put(3,"null,null");
- 首先两个线程同时取Map的值
- 使用当前时间分别替换掉value的两个null
String str = DATA_MAP.get(3);
Thread.sleep(1000);
String replaceStr = nextParam.replaceFirst("null",System.currentTimeMillis()+"");
DATA_MAP.put(nodeInfo.getNextNodeId(),replaceStr);
我现在得到的key为3的结果是:
20191233311231,null
//最后执行的会覆盖掉前一个执行的结果。 因为取值是得到的都是"null,null"
我想得到的结果是:
20191233311231,201912321321411
如何去做?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
可以上传一下完整的代码吗? 因为这里看不到另一个线程的操作。
ConcurrentHashMap是能保证一个写操作的的原子性,你这样先取出来,改完后put进去,结果肯定是这样。(一个读操作+一个写操作,ConcurrentHashMap不能保证原子性)
把
get
和put
的过程放在一起加一个锁,分开的操作不能保证原子性。可以利用
ConcurrentHashMap
的replace
方法,demo如下1、你用HashTable、Collections.synchronizedMap()、ConcurrentHashMap去存数据,而且你get和set在同一个synchronized里面。
2、再有,避免数据被覆盖,可以对key进行加锁,做一个加锁的方法,锁对象是操作的key,保证只有一个能操作,方法内部再用cas做一次判断,避免覆盖数据。
ConcurrentHashMap
只能保证单个操作的原子性,你先get再put,整个操作不是原子性操作,因此是会出现覆盖的问题的。用java.util.concurrent.ConcurrentHashMap#replace(K, V, V)
方法的话需要加上失败重试,不然在并发的情况下基本是会出现一个线程无法完成替换的情况的。这个需求使用
java.util.concurrent.ConcurrentHashMap#computeIfPresent
方法实现起来会方便一点。jdk7可能没有这个方法,需要jdk8或以上版本