使用HashMap的多线程Java Singleton Synchronization

时间:2015-07-08 07:23:29

标签: java multithreading hashmap singleton synchronized

我有以下课程:

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次调用大约抛出一次这个错误。

这个单身人士怎么了?

2 个答案:

答案 0 :(得分:1)

问题很简单,HashMaps不是线程安全的,因为您可以在链接的文档中阅读。

您应该尝试将其更改为ConcurrentHashMaps

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

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

答案 1 :(得分:1)

我认为问题出在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;
   }