我有一个包含hahsmap的单例类,hashmap初始化为类变量。此映射已正确更新,因为当我添加并打印它更改的大小时,但是,当我从不同的线程调用它时,映射始终为空。是否有可能发生这种情况的原因?
如果这有任何不同,我正在使用ConccurentHashMap。
由于
Singleton decleration:
public class ClientRegistryDetailsSingleton {
private static ClientRegistryDetailsSingleton instance = null;
private ConcurrentHashMap<String, Integer> tickerToNumberRegistered = new ConcurrentHashMap<String,Integer>();
protected ClientRegistryDetailsSingleton() {
// Exists only to defeat instantiation.
}
public static ClientRegistryDetailsSingleton getInstance() {
if(instance == null) {
instance = new ClientRegistryDetailsSingleton();
}
return instance;
}
public void setTickerToNumberRegistered(ConcurrentHashMap<String, Integer> tickerToNumberRegistered) {
this.tickerToNumberRegistered = tickerToNumberRegistered;
}
public ConcurrentHashMap<String, Integer> getTickerToNumberRegistered() {
return tickerToNumberRegistered;
}
public void addToClienets(String ticker){}
public void removeFromClients(String ticker){}
}
从另一个线程调用它:
String[] splitForTicker = message.split(",");
ConcurrentHashMap<String, Integer> map = ClientRegistryDetailsSingleton.getInstance().getTickerToNumberRegistered();
System.out.println("The number of items in the map from senders persepctive" + map.size());
输出:
来自Feed的The number of items in the map from senders persepctive 0 2012-11-12 14:29:12,495 [Process messages received] INFO com.feed.feedReceive.ProcessFeedStreamLine - Successfully received a message from the feed The number of items in the map from senders persepctive 0 1 :the size of the map now someone has added 2012-11-12 14:29:15,495 [Process messages received] INFO com.feed.feedReceive.ProcessFeedStreamLine - Successfully received a
消息 来自发件人的地图中的项目数量为0
Singleton的新代码
public class ClientRegistryDetailsSingleton {
private static ClientRegistryDetailsSingleton instance = new ClientRegistryDetailsSingleton();
private volatile ConcurrentHashMap<String, Integer> tickerToNumberRegistered = new ConcurrentHashMap<String,Integer>();
protected ClientRegistryDetailsSingleton() {
// Exists only to defeat instantiation.
}
public static synchronized ClientRegistryDetailsSingleton getInstance() {
return instance;
}
public synchronized ConcurrentHashMap<String, Integer> getTickerToNumberRegistered() {
return tickerToNumberRegistered;
}
public void addToClienets(String ticker){}
public void removeFromClients(String ticker){}
}
答案 0 :(得分:3)
如果两个线程调用getInstance()
并且尚未构造单例,则发布的代码中存在竞争条件,这可能导致构造单个实例的一个实例更多:
public static ClientRegistryDetailsSingleton getInstance() {
if(instance == null) { // Line 1
instance = new ClientRegistryDetailsSingleton(); // Line 2
}
}
可能执行两个线程T1
和T2
:
if
分支。instance
仍为null
。if
分支。instance
。instance
返回给来电者。instance
。单个实例的构造必须是线程安全的。可能的解决方案是:
getInstance()
方法synchronized
。不要使用延迟初始化(如果可能):
private static final ClientRegistryDetailsSingleton instance =
new ClientRegistryDetailsSingleton();
答案 1 :(得分:0)
将哈希地图定义为
private volatile ConcurrentHashMap<String, Integer>
volatile关键字警告JVM,变量的状态可能随时被另一个线程更改,因此不能在本地缓存。
也可能需要将实例定义为volatile。
答案 2 :(得分:0)
DCL反模式的实施:http://en.wikipedia.org/wiki/Double_checked_locking
public class ClientRegistryDetailsSingleton {
private static volatile ClientRegistryDetailsSingleton instance = null;
private final ConcurrentHashMap<String, Integer> tickerToNumberRegistered = new ConcurrentHashMap<String,Integer>();
private ClientRegistryDetailsSingleton() {
// Exists only to defeat instantiation.
// please not that constructor should be private
}
public static ClientRegistryDetailsSingleton getInstance() {
if (instance == null) {
synchronized(ClientRegistryDetailsSingleton.class){
if(instance == null)
instance = new ClientRegistryDetailsSingleton();
}
}
return instance;
}
//You should not break encapsulation and allow a link to HashMap escape
private void setTickerToNumberRegistered(ConcurrentHashMap<String, Integer> tickerToNumberRegistered) {
this.tickerToNumberRegistered = tickerToNumberRegistered;
}
//You should not break encapsulation and allow a link to HashMap escape
private ConcurrentHashMap<String, Integer> getTickerToNumberRegistered() {
}
//I omitted the access to the hash map it's likely that some additional params required
public void addToClienets(String ticker){}
//I omitted the access to the hash map it's likely some additional params are required
public void removeFromClients(String ticker){}
}
我只是作为一个同步示例展示了这一点,在现实生活中,您应该将您的单身作为枚举来实现:What is the best approach for using an Enum as a singleton in Java?