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

wal*_*len 1 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Ste*_*ker 7

不要打扰.急切地初始化Map,使场地最终,并放弃同步,直到你证明它确实是必要的.成本微不足道,"明显安全和正确"的解决方案几乎不会太慢.

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

  • 关于发明障碍的评论+1. (2认同)
  • 我确信,我将更改代码,以便在构建时初始化地图. (2认同)

Ste*_*n C 5

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

至于你的问题,答案是该synchronized块是正确性必需的.没有它,您可以获得以下事件序列.

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

简而言之,如果线程1和线程2 在具有其初始值的同时调用,则它们可以获得不同的映射.getHList()hMapnull


(在上面的,我假设getHList()是一个getter hMap.但是,正如所写的方法将无法编译,其声明的返回类型不匹配的类型hMap......所以目前还不清楚什么是真的打算去做.)