为什么我要在单线程方法中放置一个synchronized块?

Mar*_*cak 10 java multithreading volatile synchronized producer-consumer

我在IBM - developerworks上偶然发现了这篇文章,他们发布的代码让我提出了一些问题:

  1. 为什么局部变量的构建Map包含在一个synchronized块中?请注意,他们隐含地说只有一个producer线程.

  2. 实际上,为什么这个片段需要一个synchronized块呢?一个volatile变量应为工作是不够的,因为新创建的地图只被填满后公布.

  3. 什么是点只有一个线程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);

}
Run Code Online (Sandbox Code Playgroud)

Ole*_*leg 6

根据Java内存模型,在易失性写入和后续易失性读取之间存在一个先发生的关系,这意味着m = currentMap;可以保证看到之前发生的所有事情currentMap = newMap;,synchronized不需要该块.

不仅如此,它绝对没有,:

由于Java内存模型,这必须同步

在上面的同步块之后,HashMap中的所有内容都在此线程外部可见

评论是错误的.根据Java内存模型,只有当两个线程都存在时才会发生先发生关系synchronized.根据JMM,在文章中使用它绝对没有任何东西(一些JVM实现可以做一些事情,也许在2007年某些IBM JVM实现在这种情况下执行某种同步,但JMM不需要它).

总之,IBM的文章完全错了.