Java 使用 HashMap 实现多线程的单例同步
Java Singleton Synchronization for multi-thread using HashMap
我有以下 class :
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 个线程使用这个 class,它大约每 100.000 次调用抛出一次这个错误。
这个单例有什么问题?
问题很简单,HashMaps 不是线程安全的,您可以在链接文档中阅读。
您应该尝试将它们更改为 ConcurrentHashMaps。
除此之外,您还应该更改单例实现以更好地处理多线程。 Double-checked locking 上的维基百科页面提供了很多很好的示例。
p.s.: 与其将变量声明为 HashMap,不如将它们声明为 Maps。这样你就可以很容易地改变具体的实现,而不必重构任何东西。这叫做Programming to interfaces.
我认为问题出在 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;
}
我有以下 class :
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 个线程使用这个 class,它大约每 100.000 次调用抛出一次这个错误。
这个单例有什么问题?
问题很简单,HashMaps 不是线程安全的,您可以在链接文档中阅读。
您应该尝试将它们更改为 ConcurrentHashMaps。
除此之外,您还应该更改单例实现以更好地处理多线程。 Double-checked locking 上的维基百科页面提供了很多很好的示例。
p.s.: 与其将变量声明为 HashMap,不如将它们声明为 Maps。这样你就可以很容易地改变具体的实现,而不必重构任何东西。这叫做Programming to interfaces.
我认为问题出在 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;
}