Java:在创建ConcurrentHashMap对象时使用synchronized(this)是一种可行的做法吗?

时间:2013-01-30 01:27:02

标签: java multithreading web-services synchronized concurrenthashmap

我刚刚为我参加的分布式编程课程开发了一个java Web服务服务器。其中一个要求是保证我们项目的多线程安全,因此我决定使用ConcurrentHashMap对象来存储我的数据。 最后,我留下了一个关于这段代码的问题:

    public List<THost> getHList() throws ClusterUnavailable_Exception{

    logger.entering(logger.getName(), "getHList");
    if(hMap==null){
        synchronized(this){
            if(hMap==null){
                hMap=createHMap();
            }
        }
    }
    if(hMap==null){
        ClusterUnavailable cu = new ClusterUnavailable();
        cu.setMessage("Data unavailable.");
        ClusterUnavailable_Exception exc = new ClusterUnavailable_Exception("Data unavailable.", new ClusterUnavailable());
        throw exc;
    }
    else{
        List<THost> hList = new ArrayList<THost>(hMap.values());
        logger.info("Returning list of hosts. Number of hosts returned = "+hList.size());
        logger.exiting(logger.getName(), "getHList");
        return hList;
    }
}

在创建concurrenthashmap对象时,是否必须使用synchronized语句,以保证服务在多线程环境中不会出现任何不可预测的行为?

4 个答案:

答案 0 :(得分:7)

不要打扰。急切地初始化Map,使该字段成为最终,并删除同步,直到您证明它确实是必要的。成本微不足道,“明显安全和正确”的解决方案几乎不会太慢。

您提到这是一个类项目 - 专注于使代码正常工作。并发是很难的,没有发明你必须跨越的额外障碍。

答案 1 :(得分:5)

简单的解决方案是通过急切初始化来避免问题。除非你有明确的证据(即分析),急切的初始化是一个性能问题,这也是最好的解决方案。

关于您的问题,答案是synchronized正确 。没有它,您可以获得以下事件序列。

  • 主题1调用getHList()
  • 主题1看到hMapnull并开始创建地图。
  • 主题2调用getHList()
  • 主题2看到hMapnull并开始创建地图。
  • 主题1完成创建,并将新地图分配给hMap,然后返回该地图。
  • 线程2完成创建,并将第二个新地图分配给hMap,然后返回该地图。

简而言之,如果线程1和线程2同时调用getHList()hMap具有其初始null值,则可以获取不同的地图。


(在上面,我假设getHList()hMap的getter。但是,编写的方法不会编译,并且其声明的返回类型与类型不匹配hMap ...所以不清楚它真正打算做什么。)

答案 2 :(得分:1)

以下行与ConcurrentHashMap无关。它只是创建一个ConcurrentHashMap对象的实例。 就像在JAVA中同步任何对象一样。

hMap=new ConcurrentHashMap<BigInteger, THost>();

答案 3 :(得分:0)

在Java 1.5之前,双重检查锁定模式被破坏(在Java 1.6及更高版本中效率很低)。请参阅:http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

考虑使用按需初始化持有者或单个元素枚举类型。