这个模式的名称? (答案:使用双重检查锁定进行延迟初始化)

请考虑以下代码:

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(); } } 

首先,我需要说明一些假设:

  1. 有一个很好的理由我不能只是一个应用程序启动时这样做。 也许数据还没有,等等。

  2. Foo可以被实例化并且从两个或更多个线程同时使用。 我希望其中一个最终创建一些数据(但不是两个)然后我将允许两者访问相同的数据(忽略访问数据的线程安全性)

  3. SomeDataDoesNotExist()的成本并不高。

现在,这不一定要局限于某些数据创建情况,但这是我能想到的一个例子。

我特别感兴趣的是识别模式的部分是check – > lock – > check。 我不得不在开发人员的某些情况下向他们解释这种模式,他们乍一看并没有得到算法,但可以欣赏它。

无论如何,其他人必须做同样的事情。 这是一个标准化的模式吗? 它叫什么?

使用双重检查锁定进行延迟初始化?

虽然我可以看到你怎么认为这看起来像双重检查锁定,它实际上看起来是危险的破坏和不正确的双重检查锁定 。 如果没有SomeDataDoesNotExist和CreateSomeData的实际实现来批评,我们无法保证这个东西在每个处理器上实际上都是线程安全的。

有关双重检查锁定可能出错的分析示例,请查看此双重检查锁定的错误和错误版本:

C#手动锁定/解锁

我的建议:如果没有令人信服的理由,请不要使用任何低锁技术,也不要使用内存模型专家的代码审查; 你可能会弄错。 大多数人这样做。

特别是,不要使用双重检查锁定,除非您可以准确描述处理器可以代表您执行的内存访问重新排序,并提供令人信服的论据,即在任何可能的内存访问重新排序的情况下 ,您的解决方案是正确的。 当你从一个已知的正确实现中稍微离开的那一刻起,你需要从头开始分析。 你不能假设只是因为一个双重检查锁定的实现是正确的,它们都是正确的; 几乎没有一个是正确的。

我特别感兴趣的是识别模式的部分是check – > lock – > check。

这称为双重检查锁定 。

请注意,在较旧的Java版本(Java 5之前)中,由于Java的内存模型的定义方式,它并不安全。 在Java 5中,对Java的内存模型的规范进行了更新的更改,以便它现在是安全的。

对于这种类型,唯一想到的名字是“Faulting”。 此名称在iOS Core-Data框架中用于类似的效果。

基本上,您的方法NameDoesNotMatter是一个错误 ,每当有人调用它时,它都会导致对象被填充或初始化。

有关如何使用此设计模式的更多详细信息,请参阅http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdFaultingUniquing.html 。