【问题标题】:Java Singleton Synchronization for multi-thread using HashMap使用HashMap的多线程Java单例同步
【发布时间】:2015-09-25 23:20:22
【问题描述】:

我有以下课程:

public class AggregationController {


    private HashMap<String, TreeMap<Integer, String>> messages; 
    private HashMap<String, Integer> counters;  
    Boolean buildAggregateReply;
    private boolean isAggregationStarted;

    private static HashMap<String, AggregationController> instances = new HashMap<String, AggregationController>();

    private AggregationController() throws MbException{
        messages = new HashMap<String, TreeMap<Integer,String>>();
        counters = new HashMap<String, Integer>();
        buildAggregateReply = true;
        isAggregationStarted = false;
    }

    public static synchronized AggregationController getInstance(String id) throws MbException{
        if(instances.get(id) == null)
            instances.put(id, new AggregationController());
        return instances.get(id);
    }   

我认为避免并发访问就足够了,但我得到了这个错误:

HashMap.java
checkConcurrentMod
java.util.HashMap$AbstractMapIterator
java.util.ConcurrentModificationException
Unhandled exception in plugin method
java.util.ConcurrentModificationException

我有 10 个线程在使用这个类,它大约每 100.000 次调用就会引发一次这个错误。

这个单例有什么问题?

【问题讨论】:

  • 完整的堆栈跟踪以及您看到发生此异常的代码?
  • 你会同步课堂内地图上的调用吗?也许这些访问可能会导致问题?
  • 我发现了问题。其中一个函数(此处未写)试图访问与 get 实例相同的对象。这两个函数是单独同步的,但可以同时调用为了解决这个问题,我将其更改为 ConcurrentHashMap,并且我还通过使用双重检查锁定改进了同步。现在我会整晚运行测试,让你知道问题是否真的解决了

标签: java multithreading hashmap singleton synchronized


【解决方案1】:

问题只是 HashMaps 不是线程安全的,正如您可以在链接的文档中看到的那样。

您应该尝试将它们更改为ConcurrentHashMaps

除此之外,您还应该更改单例实现以更好地处理多线程。 Double-checked locking 上的维基百科页面提供了很多很好的例子。

p.s.:不要将变量声明为 HashMaps,而应将它们声明为 Maps。这样,您可以非常轻松地更改特定的实现,而无需重构任何东西。这称为Programming to interfaces

【讨论】:

  • 看来它解决了我的问题,我今晚会做一些大规模测试以确定。非常感谢所有提示
【解决方案2】:

我认为问题出在HashMap,请使用Concurrent HashMap

但我想说的是,你的getInstnace() 函数写得不好。

       public static synchronized AggregationController getInstance(String id) throws MbException{
    if(instances.get(id) == null)
        instances.put(id, new AggregationController());
    return instances.get(id);
}   

您在整个方法中使用synchronized。即使您的实例已创建,也只有一个线程能够进入getInstance 方法,这会降低您的程序性能。你应该像this

      public static AggregationController getInstance() {
           if (instance == null ) {
           synchronized (AggregationController.class) {
             if (instance == null) {
                 instance = new AggregationController();
             }
          }
      }

      return instance;
   }

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-06
  • 2012-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多