Hashmap并发问题

Nat*_*ath 30 java concurrency

我有一个Hashmap,出于速度原因,我不想要锁定.如果我不介意陈旧的数据,那么更新它并同时访问它会导致任何问题吗?

我的访问是获取,而不是遍历它,删除是更新的一部分.

eri*_*son 56

是的,这会造成重大问题.一个例子是在向哈希映射添加值时可能发生的情况:这可能导致表的重新哈希,如果在另一个线程迭代冲突列表(哈希表"桶")时发生,则该线程可能会错误地无法找到地图中存在的密钥.HashMap对于并发使用显然是不安全的.

ConcurrentHashMap改用.


Gar*_*vis 16

不能低估同步或使用ConcurrentHashMap的重要性.

直到几年前,我才被误导了,我只能在HashMap上同步put和remove操作.这当然是非常危险的,实际上在HashMap.get()中导致了一些无限循环(我认为早期的1.5)jdk.

几年前我做了什么(真的不应该这样做):

public MyCache {
    private Map<String,Object> map = new HashMap<String,Object>();

    public synchronzied put(String key, Object value){
        map.put(key,value);
    }

    public Object get(String key){
        // can cause in an infinite loop in some JDKs!!
        return map.get(key);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:以为我想补充的是什么一个例子这样做(见上文)

  • 我认为无限循环是每个Sun JDK的一个特性.我不记得哪一个众所周知的开源软件正在使用HashMap进行日志记录,因此不需要同步速度,因为不需要完全准确.在生产中,非常偶尔会进入无限循环 - 比抛出未经检查的异常更糟糕. (4认同)

mat*_*t b 12

如有疑问,请检查班级的Javadocs:

请注意,此实现不同步.如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步.(结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已包含的键关联的值不是结构修改.)这通常通过同步自然封装映射的某个对象来完成. .如果不存在此类对象,则应使用Collections.synchronizedMap方法"包装"该映射.这最好在创建时完成,以防止意外地不同步访问地图:

Map m = Collections.synchronizedMap(new HashMap(...));

(强调不是我的)

所以基于你说你的线程将从Map中删除映射的事实,答案是肯定它肯定会导致问题,是的,它肯定是不安全的.


yka*_*ich 10

是.非常糟糕的事情会发生.例如,您的线程可能陷入无限循环.

使用ConcurrentHashMapNonBlockingHashMap


Kat*_*one 7

您描述的条件不会得到满足HashMap.由于更新地图的过程不是原子的,因此您可能会遇到无效状态的地图.多次写入可能会使其处于损坏状态. ConcurrentHashMap(1.5或更高版本)可以满足您的需求.