我正在使用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);
}
是否有必要同步(或挥发)地图引用,因为我将只允许通过updateMap方法更新地图(已同步)?
将在多个线程中访问(读取)地图对象,尤其是通过迭代器。知道迭代器会在后端地图的结构发生变化时抛出异常,我想我会使地图不可修改。因此,当我通过updateMap更改地图的结构时,现有的迭代器将继续处理“旧”地图(这对我来说很好)。
副作用是,我不必担心同步读取。在本质上,与写入相比,我将具有更大的读取幅度。当前正在迭代地图对象的线程将继续这样做,任何启动的新线程都将获取最新的地图。 (好吧,我假设它会在这里考虑erickson的评论 - Java concurrency scenario -- do I need synchronization or not?)
有人可以评论这个想法是否合适吗?
谢谢!
答案 0 :(得分:6)
您应该使用volatile
关键字,以确保线程会看到最新的Map
版本。否则,如果没有同步,则没有保证其他线程将看到除空地图之外的任何内容。
由于updateMap()
已同步,因此对其的每次访问都会看到map
的最新值。因此,您不会丢失任何更新。这是有保证的。但是,由于getMap()
未同步且map
不是volatile
,因此无法保证线程会看到map
的最新值,除非该线程本身是最新的线程来更新地图。使用volatile
将解决此问题。
但是,您执行可以访问Java 1.5和1.6并发添加项。存在backport。我强烈建议使用backport,因为当您能够迁移到更高版本的JDK时,它将允许轻松迁移到JDK并发类,并且它允许比您的方法更高的性能。 (虽然如果您map
的更新很少,那么您的表现应该没问题。)
答案 1 :(得分:1)
从技术上讲,如果使用volatile map,则不需要同步updateMap(更新'map'是原子的,并且该方法中的所有其他指令都在当前线程的本地对象上运行)。
答案 2 :(得分:0)
我知道这不是你问题的一部分。但是,如果您担心并发性并且不使用Java 1.5 for ConcurrentHashMap。使用Hashtable的不可变实例。它是一个阻塞并发映射实现,它处理所有并发写入和读取。