带有hashmap的廉价读写锁


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);

}

这是本文中的一个代码示例https://www.ibm.com/developerworks/library/j-hashmap/index.html我仍然不明白为什么我们需要在buildNewMap方法中使用同步块。除了currentMap=newMap的不稳定发布之外,还有什么额外的可见性可以保证它产生;做当我们在m=currentMap;我们依赖volatile读写线程,而reading线程甚至不知道生产者线程中的同步。。。。

如果在将hashmap写入"currentMap"之前只对其进行了修改,则保证其内容对其他线程可见。这是因为在写入映射内容和写入currentMap(程序顺序(之间存在先发生后发生的边缘;在读取concurrentMap之间有一个发生前边缘(volatile变量(,在读取变量和读取内容(程序顺序(之间有一条发生前边缘。由于发生在前面是可传递的,所以在编写内容和阅读内容之间存在发生在前面的边缘。

同步块似乎没有任何作用。

Java内存模型为易失性写入提供了强有力的保证,根据本文:

http://tutorials.jenkov.com/java-concurrency/volatile.html

特别是:

  • 如果线程A写入一个易失性变量,而线程B随后读取同一个易发性变量,那么线程A在写入易失性可变变量之前可见的所有变量,在线程B读取易失性变量之后也将可见
  • 如果线程A读取一个易失性变量,那么线程A在读取该易失性时可见的所有变量也将从主存中重新读取

所以看起来同步块是不必要的。

最新更新