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

时间:2018-03-16 21:22:38

标签: java multithreading synchronized volatile producer-consumer

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

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

  2. 实际上,为什么这个片段根本不需要synchronized块? volatile变量对于作业来说应该足够了,因为新创建的地图仅在填充后才会发布。

  3. 锁定对象上只有一个线程synchronizing有什么意义?

  4. 文章提到:

      

    清单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);
    
    }
    

1 个答案:

答案 0 :(得分:6)

根据Java memory model,在易失性写入和后续易失性读取之间存在发生在之前的关系,这意味着m = currentMap;可以保证看到发生的一切在currentMap = newMap;之前,不需要synchronized块。

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

  

由于Java内存模型

,必须同步

  

在上面的同步块之后,HashMap中的所有内容都是      在此主题之外可见

评论错了。根据Java内存模型,只有当两个线程都是synchronized时才会有发生在之前的关系;根据{{​​3}}(某些JMM实现可以做一些事情并且在2007年某些IBM JVM实现在这种情况下执行某种同步,但是JMM没有要求它。)

总之,IBM的文章完全没错。