不可修改的地图是否需要同步?

Tim*_*ddy 2 java concurrency

我正在使用JDK 1.4 ...所以我无法访问1.5+中的好并发内容.

考虑以下类片段:

private Map map = Collections.EMPTY_MAP;

public Map getMap() {
    return map;
}

public synchronized void updateMap(Object key, Object value) {
    Map newMap = new HashMap(map);
    newMap.put(key, value);
    map = Collections.unmodifiableMap(newMap);
}
Run Code Online (Sandbox Code Playgroud)

是否有必要同步(或挥发)地图引用,因为我将只允许通过updateMap方法(已同步)更新地图?

将在多个线程中访问(读取)map对象,尤其是通过Iterators.知道迭代器会在后端地图的结构发生变化时抛出异常,我想我会使地图不可修改.因此,当我通过updateMap更改地图的结构时,现有的迭代器将继续处理"旧"地图(这对我来说很好).

副作用是,我不必担心同步读取.在本质上,与写入相比,我将具有更大的读取幅度.当前正在迭代地图对象的线程将继续这样做,任何启动的新线程都将获取最新的地图.(好吧,我假设它会在这里考虑erickson的评论 - Java并发场景 - 我是否需要同步?)

有人可以评论这个想法是否合适吗?

谢谢!

Edd*_*die 6

应该使用volatile关键字,以确保线程将看到最新Map版本.否则,如果没有同步,则无法保证其他线程除了空映射外都会看到任何内容.

由于您updateMap()已同步,因此每次访问它都会看到最新值map.因此,您不会丢失任何更新.这是有保证的.但是,因为你的getMap()不同步而map不是volatile,也不能保证一个线程将看到最新的值map,除非该线程本身是最近的线程来更新地图.使用volatile会解决这个问题.

但是,您可以访问的Java 1.5和1.6并发补充.存在一个后端口.我强烈建议使用backport,因为当您能够迁移到更高版本的JDK时,它将允许轻松迁移到JDK并发类,并且它允许比您的方法更高的性能.(虽然如果您的更新map很少见,那么您的表现应该没问题.)

  • 我的理解是,对于JDK 1.4中的单个变量**,volatile的工作正如您所期望的那样.但是,在JDK 1.5中,JMM得到了加强,因此对volatile变量的写入会产生"之前发生",这保证了在volatile写入之前发生的所有写入的内存同步.但由于上述评论中提到的原因,我强烈建议使用backport. (4认同)
  • Volatile不能保证工作到1.5,所以你应该使用backport. (2认同)