此模式的名称?(答案:带有双重检查锁定的延迟初始化)
本文关键字:检查 锁定 延迟 初始化 模式 答案 | 更新日期: 2023-09-27 17:56:35
请考虑以下代码:
public class Foo
{
private static object _lock = new object();
public void NameDoesNotMatter()
{
if( SomeDataDoesNotExist() )
{
lock(_lock)
{
if( SomeDataDoesNotExist() )
{
CreateSomeData();
}
else
{
// someone else also noticed the lack of data. We
// both contended for the lock. The other guy won
// and created the data, so we no longer need to.
// But once he got out of the lock, we got in.
// There's nothing left to do.
}
}
}
}
private bool SomeDataDoesNotExist()
{
// Note - this method must be thread-safe.
throw new NotImplementedException();
}
private bool CreateSomeData()
{
// Note - This shouldn't need to be thread-safe
throw new NotImplementedException();
}
}
首先,我需要陈述一些假设:
有一个很好的理由,我不能在应用程序启动后立即执行此操作。 也许数据尚不可用,等等。
Foo可以从两个或多个线程实例化并发使用。 我希望其中一个最终创建一些数据(但不是两个),然后我将允许两个访问相同的数据(忽略访问数据的线程安全性)
SomeDataDoesNotExist() 的成本并不高。
现在,这不一定仅限于某些数据创建情况,但这是我能想到的一个例子。
我特别感兴趣的识别模式的部分是检查 -> 锁定 -> 检查。 我不得不几次向开发人员解释这种模式,他们乍一看并不了解算法,但随后可以欣赏它。
无论如何,其他人也必须这样做。 这是一个标准化的模式吗? 叫什么?
虽然我可以看到您可能认为这看起来像双重检查锁定,但它实际上看起来像是危险的损坏和不正确的双重检查锁定。如果没有SomeDataDoesNotExist和CreateSomeData的实际实现来批评,我们无法保证这个东西在每个处理器上都是线程安全的。
有关双重检查锁定如何出错的分析示例,请查看此损坏且不正确的双重检查锁定版本:
C# 手动锁定/解锁
我的建议是:如果没有令人信服的理由和内存模型专家的代码审查,不要使用任何低锁技术;你可能会弄错。大多数人都会这样做。
特别是,不要使用双重检查锁定,除非您能够准确描述处理器可以代表您执行的内存访问重新排序,并提供令人信服的论据,说明您的解决方案在任何可能的内存访问重新排序的情况下是正确的。一旦你稍微远离一个已知的正确实现,你也需要从头开始分析。您不能仅仅因为双重检查锁定的一个实现是正确的,就假设它们都是正确的;几乎没有一个是正确的。
使用双重检查锁定进行延迟初始化?
我特别感兴趣的识别模式的部分是检查 -> 锁定 -> 检查。
这称为双重检查锁定。
请注意,在较旧的Java版本(Java 5之前)中,由于Java的内存模型是如何定义的,因此它是不安全的。在 Java 5 中,对 Java 内存模型的规范进行了更新的更改,因此它现在是安全的。
这种,唯一想到的名称是"错误"。此名称在 iOS 核心数据框架中使用,具有类似的效果。
基本上,您的方法 NameDoesNotMatter 是一个错误,每当有人调用它时,它都会导致对象被填充或初始化。
有关如何使用此设计模式的更多详细信息,请参阅 http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdFaultingUniquing.html。