我有一个单身人士课程:
public class MySingleton {
private static MySingleton instance;
// here the Map entry's value is also a Map
private Map<String, Map> dataMap;
private MySingleton() {
dataMap = new HashMap<String, Map>();
Map<String, String> dataTypeOneMap = new HashMap<String, String>();
Map<String, String> dataTypeTwoMap = new HashMap<String, String>();
dataMap.put("dataTypeOne", dataTypeOneMap);
dataMap.put("dataTypeTwo", dataTypeTwoMap);
}
public static MySingleton getInstance() {
if(instance == null) {
instance = new MySingleton();
}
return instance;
}
public synchronized void storeData(String data, String type) {
dataMap.get(type).put("my_data", data);
}
public synchronized String getData(type) {
return dataMap.get(type).get("my_data");
}
}
多个线程可以访问公共方法storeData(...)
&amp; getData(...)
。 e.g:
MySingleton.getInstance().storeData("hello", "dataTypeOne");
MySingleton.getInstance().getData("dataTypeOne");
我需要ConcurrentHashMap
使用dataMap
类型吗?或者它已经是线程安全的?我觉得我的代码已经是线程安全的,但只是想确保没有角落案例会破坏它。感谢。
答案 0 :(得分:4)
根据注释,实例的延迟实例化不是线程安全的,即如果2个线程同时调用getInstance()
两个调用都可能导致instance = new MySingleton();
,甚至返回不同的instance
意味着两个线程都在不同的对象上运行。
要解决此问题,您可以在类本身上同步getInstance()
,甚至使用双重检查锁定来减少同步开销(如果您不能首先删除延迟):
private volatile MySingleton instance;
public static MySingleton getInstance() {
//check if the instance doesn't exist yet, this is not threadsafe
if(instance == null) {
//the instance doesn't exist yet so synchronize and check again, since another thread
// might have entered this block in the meantime and instance is not null anymore
synchronized(MySingleton.class) {
if(instance == null) {
instance = new MySingleton();
}
}
}
return instance;
}
使用双重检查锁定,你只能同步创建部分,检查null并返回实例,如果它不是null,则不必是线程安全的。
答案 1 :(得分:1)
简短回答:
这部分代码不是线程安全的:
public static MySingleton getInstance() {
if(instance == null) {
instance = new MySingleton();
}
return instance;
}
答案很长
让我们一个一个地处理代码部分。
例如,假设一个线程正在执行 getInstance 方法并达到if条件:
if(instance == null) {
现在,如果另一个线程开始调用该方法,则if条件仍为true,并且还将尝试创建新实例。所以它可能会创建一些用例:
<强>解决方案:强>
同步实例创建块:
synchronized(MySingleton.class){
if(instance == null) {
instance = new MySingleton();
}
}
答案 2 :(得分:0)
不,它不是线程安全的。使用ConcurrentHashMap允许从不同的线程进行访问和修改。它还允许您在没有性能命中的情况下异步读取地图。
同步getInstance()方法,并最小化对该方法的调用量 - 在另一个线程上运行的每个对象上存储对单例的引用以防止重复的getInstance()调用将有所帮助。
答案 3 :(得分:0)
线程安全的Singleton
您可以通过以下帖子定义线程安全的LazySingleton:
Why is volatile used in this example of double checked locking
您的class A:
def __init__(self, items):
self.items = list(items) # or items[:]
li = [1, 2]
obj = A(li)
li[0] = 9
print(obj.items)
# [1, 2]
是线程安全的。但您可以进一步优化代码。您可以将dataMap
替换为Map
,并删除ConcurrentHashMap
和synchronized
方法中的storeData
。
您可以查看有关high level concurrency
的此文档页面