为什么要在单线程方法中放置同步块?
Why would I place a synchronized block within a single-threaded method?
我在 IBM - developerworks 上偶然发现 this article,他们发布的代码让我提出了一些问题:
为什么局部变量 Map
的构建包含在 synchronized
块中?请注意,他们含蓄地说只有一个 producer
线程。
实际上,为什么这个片段需要一个 synchronized
块?一个 volatile
变量就足够了,因为新创建的地图只有在填满后才会发布。
锁对象上只有一个线程synchronizing
有什么意义?
文章提到:
The synchronized block and the volatile keyword in Listing 1 are required because no happens-before relationship exists between the writes to the currentMap and the reads from currentMap. As a result, reading threads could see garbage if the synchronized block and the volatile keyword were not used.
代码中的注释是:
this must be synchronized because of the Java memory model
我觉得我正在处理超出我理解范围的多线程概念;我希望有更多专业知识的人为我指明正确的方向。
这是从文章中摘录的片段:
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);
}
根据 Java memory model,易失性写入和后续易失性读取之间存在 happens-before 关系,这意味着 m = currentMap;
保证看到 currentMap = newMap;
之前发生的一切,不需要 synchronized
块。
不仅如此,它什么也没做,:
this must be synchronized because of the Java memory model
和
After the above synchronization block, everything that is in the HashMap is
visible outside this thread
评论有误。根据 Java 内存模型,只有当两个线程都是 synchronized
时,才会存在 happens-before 关系;根据 JMM (some JVM 实现,按照文章中的方式使用它绝对没有任何作用,也许 2007 年的某些 IBM JVM 实现在这种情况下执行了某种同步,但 JMM 不需要它)。
总之,IBM 的文章是完全错误的。
我在 IBM - developerworks 上偶然发现 this article,他们发布的代码让我提出了一些问题:
为什么局部变量
Map
的构建包含在synchronized
块中?请注意,他们含蓄地说只有一个producer
线程。实际上,为什么这个片段需要一个
synchronized
块?一个volatile
变量就足够了,因为新创建的地图只有在填满后才会发布。锁对象上只有一个线程
synchronizing
有什么意义?
文章提到:
The synchronized block and the volatile keyword in Listing 1 are required because no happens-before relationship exists between the writes to the currentMap and the reads from currentMap. As a result, reading threads could see garbage if the synchronized block and the volatile keyword were not used.
代码中的注释是:
this must be synchronized because of the Java memory model
我觉得我正在处理超出我理解范围的多线程概念;我希望有更多专业知识的人为我指明正确的方向。
这是从文章中摘录的片段:
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);
}
根据 Java memory model,易失性写入和后续易失性读取之间存在 happens-before 关系,这意味着 m = currentMap;
保证看到 currentMap = newMap;
之前发生的一切,不需要 synchronized
块。
不仅如此,它什么也没做,:
this must be synchronized because of the Java memory model
和
After the above synchronization block, everything that is in the HashMap is visible outside this thread
评论有误。根据 Java 内存模型,只有当两个线程都是 synchronized
时,才会存在 happens-before 关系;根据 JMM (some JVM 实现,按照文章中的方式使用它绝对没有任何作用,也许 2007 年的某些 IBM JVM 实现在这种情况下执行了某种同步,但 JMM 不需要它)。
总之,IBM 的文章是完全错误的。