廉价读写锁与哈希映射

huangapple go评论58阅读模式
英文:

Cheap read-write lock with hashmap

问题

static volatile Map currentMap = null;   // this must be volatile
static Object lockbox = new Object();  

public static void buildNewMap() {      
    Map newMap = new HashMap();         
 
    synchronized (lockbox) {                
        // .. do stuff to put things in newMap
        newMap.put(....);
        newMap.put(....);
    }                 
    currentMap = newMap;
}

public static Object getFromCurrentMap(Object key) {
    Map m = null;
    Object result = null;
 
    m = currentMap;               
    if (m != null) {              
        Object result = m.get(key); 
        // Do any additional processing needed using the result
    }
    return(result);
}

这段代码示例来自于这篇文章:https://www.ibm.com/developerworks/library/j-hashmap/index.html

我仍然不明白为什么在buildNewMap方法中需要同步块。除了在currentMap = newMap;处进行volatile发布之外,它还产生了什么其他可见性保证呢?
当我们在m = currentMap;处读取地图引用时,我们依赖于volatile读写,并且读取线程甚至不知道生产者线程中的同步....

英文:
 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);
 
}

This is a code sample from this article https://www.ibm.com/developerworks/library/j-hashmap/index.html
I still don't understand why we need a synchronized block in buildNewMap method. What additional visibility guarantees it produces beside that volatile publishing at currentMap = newMap; does.
When we read map reference at m = currentMap; we rely upon volatile read-write and reading thread doesn't even know about syncronization in producer thread....

答案1

得分: 1

如果哈希映射仅在写入“currentMap”之前进行修改,则其内容保证对其他线程可见。这是因为在写入映射内容和写入到currentMap(程序顺序)之间存在happens before边缘;并且在读取concurrentMap时存在happens-before边缘(易失性变量),在读取变量和读取内容之间存在happens before边缘(程序顺序)。由于happens before是传递的,因此在写入内容和读取内容之间存在happens before边缘。

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

英文:

If the hashmap is only modified before it is written to the 'currentMap' its content is guaranteed to be visible to other threads. This is because there is a happens before edge between writing map content and writing to currentMap (program order); and there is a happens-before edge (volatile variable) between reading the concurrentMap, and there is a happens before edge between reading the variable and reading the content (program order). Since happens before is transitive, there is a happens beforge edge between writing the content and reading the content.

The synchronized block doesn't seem to serve any purpose.

答案2

得分: -1

Java内存模型对于volatile写操作提供了强大的保证,根据这篇文章:

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

具体来说:

  • 如果线程A对一个volatile变量进行写操作,然后线程B随后读取同一个volatile变量,那么在线程A写入volatile变量之前对线程A可见的所有变量,在线程B读取完volatile变量之后也将对线程B可见。
  • 如果线程A读取一个volatile变量,那么在线程A读取volatile变量时对线程A可见的所有变量也将会重新从主内存中读取。

因此看起来同步块是不必要的。

英文:

Java memory model provides strong guarantees regarding volatile writes, according to this article:

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

In particular:

> * If Thread A writes to a volatile variable and Thread B subsequently reads the same volatile variable, then all variables visible to Thread A before writing the volatile variable, will also be visible to Thread B after it has read the volatile variable.
> * If Thread A reads a volatile variable, then all all variables visible to Thread A when reading the volatile variable will also be re-read from main memory.

So it looks like the synchronized block is unnecessary.

huangapple
  • 本文由 发表于 2020年7月28日 23:52:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/63138098.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定