- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个用于许多单例实现的通用接口(interface)。接口(interface)定义了可以抛出检查异常的初始化方法。
我需要一个工厂来按需返回缓存的单例实现,想知道以下方法是否线程安全?
UPDATE1:请不要建议任何第三部分库,因为由于可能的许可问题,这将需要获得法律许可:-)
更新 2:此代码可能会在 EJB 环境中使用,因此最好不要产生额外的线程或使用类似的东西。
interface Singleton
{
void init() throws SingletonException;
}
public class SingletonFactory
{
private static ConcurrentMap<String, AtomicReference<? extends Singleton>> CACHE =
new ConcurrentHashMap<String, AtomicReference<? extends Singleton>>();
public static <T extends Singleton> T getSingletonInstance(Class<T> clazz)
throws SingletonException
{
String key = clazz.getName();
if (CACHE.containsKey(key))
{
return readEventually(key);
}
AtomicReference<T> ref = new AtomicReference<T>(null);
if (CACHE.putIfAbsent(key, ref) == null)
{
try
{
T instance = clazz.newInstance();
instance.init();
ref.set(instance); // ----- (1) -----
return instance;
}
catch (Exception e)
{
throw new SingletonException(e);
}
}
return readEventually(key);
}
@SuppressWarnings("unchecked")
private static <T extends Singleton> T readEventually(String key)
{
T instance = null;
AtomicReference<T> ref = (AtomicReference<T>) CACHE.get(key);
do
{
instance = ref.get(); // ----- (2) -----
}
while (instance == null);
return instance;
}
}
我不完全确定第 (1) 和 (2) 行。我知道引用的对象在 AtomicReference
中声明为 volatile 字段,因此在第 (1) 行所做的更改应该在第 (2) 行立即可见 - 但仍有一些疑问......
除此之外 - 我认为 ConcurrentHashMap
的使用解决了将新 key 放入缓存的原子性问题。
你们看到这种方法有什么问题吗?谢谢!
P.S.:我知道静态持有者类惯用语 - 由于 ExceptionInInitializerError
(在单例实例化过程中抛出的任何异常都被包装到其中),我没有使用它,并且随后的 NoClassDefFoundError
这不是我想要捕捉的。相反,我想通过捕获并优雅地处理它来利用专用检查异常的优势,而不是解析 EIIR 或 NCDFE 的堆栈跟踪。
最佳答案
您已经做了很多工作来避免同步,我认为这样做的原因是出于性能考虑。您是否测试过与同步解决方案相比,这是否真的提高了性能?
我问的原因是并发类往往比非并发类慢,更不用说原子引用的附加重定向级别了。根据您的线程争用,简单的同步解决方案实际上可能更快(并且更容易验证正确性)。
此外,我认为在调用 instance.init() 期间抛出 SingletonException 时,您可能会以无限循环结束。原因是在 readEventually 中等待的并发线程永远不会找到它的实例(因为在另一个线程初始化实例时抛出异常)。也许这对您的情况来说是正确的行为,或者您可能想为实例设置一些特殊值以触发将异常抛出到等待线程。
关于java - 单例对象工厂 : is this code thread-safe?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8331413/
我最近购买了《C 编程语言》并尝试了 Ex 1-8这是代码 #include #include #include /* * */ int main() { int nl,nt,nb;
早上好!我有一个变量“var”,可能为 0。我检查该变量是否为空,如果不是,我将该变量保存在 php session 中,然后调用另一个页面。在这个新页面中,我检查我创建的 session 是否为空,
我正在努力完成 Learn Python the Hard Way ex.25,但我无法理解某些事情。这是脚本: def break_words(stuff): """this functio
我是一名优秀的程序员,十分优秀!