我在 IBM - developerworks 上偶然发现了this article,他们发布的代码让我提出了一些问题:
为什么局部变量Map
的构建包含在synchronized
块中?请注意,他们隐含地说只有一个producer
线程。
实际上,为什么这个片段根本不需要synchronized
块? volatile
变量对于作业来说应该足够了,因为新创建的地图仅在填充后才会发布。
锁定对象上只有一个线程synchronizing
有什么意义?
文章提到:
清单1中的synchronized块和volatile关键字是必需的,因为在对currentMap的写入和从currentMap的读取之间不存在先前发生的关系。因此,如果未使用synchronized块和volatile关键字,则读取线程可能会看到垃圾。
代码中的评论说:
由于Java内存模型
,必须同步
我觉得我在理解之外处理多线程概念;我希望有更多专业知识的人指出我的方向正确。
以下是文章摘录:
static volatile Map currentMap = null; // this must be volatile
static Object lockbox = new Object();
public static void buildNewMap() { // this is called by the producer
Map newMap = new HashMap(); // when the data needs to be updated
synchronized (lockbox) { // this must be synchronized because
// of the Java memory model
// .. do stuff to put things in newMap
newMap.put(....);
newMap.put(....);
}
/* After the above synchronization block, everything that is in the HashMap is
visible outside this thread */
/* Now make the updated set of values available to the consumer threads.
As long as this write operation can complete without being interrupted,
and is guaranteed to be written to shared memory, and the consumer can
live with the out of date information temporarily, this should work fine */
currentMap = newMap;
}
public static Object getFromCurrentMap(Object key) {
Map m = null;
Object result = null;
m = currentMap; // no locking around this is required
if (m != null) { // should only be null during initialization
Object result = m.get(key); // get on a HashMap is not synchronized
// Do any additional processing needed using the result
}
return(result);
}
答案 0 :(得分:6)
根据Java memory model,在易失性写入和后续易失性读取之间存在发生在之前的关系,这意味着m = currentMap;
可以保证看到发生的一切在currentMap = newMap;
之前,不需要synchronized
块。
不仅如此,它绝对没有,:
由于Java内存模型
,必须同步
和
在上面的同步块之后,HashMap中的所有内容都是 在此主题之外可见
评论错了。根据Java内存模型,只有当两个线程都是synchronized
时才会有发生在之前的关系;根据{{3}}(某些JMM实现可以做一些事情并且在2007年某些IBM JVM实现在这种情况下执行某种同步,但是JMM没有要求它。)
总之,IBM的文章完全没错。