这个图案的名字? (答案:带有双重检查锁定的延迟初始化)

发布于 2024-11-07 09:15:15 字数 1460 浏览 0 评论 0原文

考虑以下代码:

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() 的成本并不大.

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

我对识别为模式特别感兴趣的部分是检查 ->锁->查看。我曾多次向开发人员解释这种模式,他们乍一看并没有理解该算法,但随后就会欣赏它。

无论如何,其他人也必须这样做。这是标准化模式吗?它叫什么?

Consider the following code:

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

First, there are some assumptions I need to state:

  1. There is a good reason I couldn't just do this once an app startup. Maybe the data wasn't available yet, etc.

  2. Foo may be instantiated and used concurrently from two or more threads. I want one of them to end up creating some data (but not both of them) then I'll allow both to access that same data (ignore thread safety of accessing the data)

  3. The cost to SomeDataDoesNotExist() is not huge.

Now, this doesn't necessarily have to be confined to some data creation situation, but this was an example I could think of.

The part that I'm especially interested in identifying as a pattern is the check -> lock -> check. I've had to explain this pattern to developers on a few occasions who didn't get the algorithm at first glance but could then appreciate it.

Anyway, other people must do similarly. Is this a standardized pattern? What's it called?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

那一片橙海, 2024-11-14 09:15:15

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

有关双重检查锁定如何出错的分析示例,请查看双重检查锁定的损坏且不正确的版本:

C# 手动锁定/解锁

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

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

Though I can see how you might think this looks like double-checked locking, what it actually looks like is dangerously broken and incorrect double-checked locking. Without an actual implementation of SomeDataDoesNotExist and CreateSomeData to critique we have no guarantee whatsoever that this thing is actually threadsafe on every processor.

For an example of an analysis of how double-checked locking can go wrong, check out this broken and incorrect version of double-checked locking:

C# manual lock/unlock

My advice: don't use any low-lock technique without a compelling reason and a code review from an expert on the memory model; you'll probably get it wrong. Most people do.

In particular, don't use double-checked locking unless you can describe exactly what memory access reorderings the processors can do on your behalf and provide a convincing argument that your solution is correct given any possible memory access reordering. The moment you step away even slightly from a known-to-be-correct implementation, you need to start the analysis over from scratch. You can't assume that just because one implementation of double-checked locking is correct, that they all are; almost none of them are correct.

小伙你站住 2024-11-14 09:15:15

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

Lazy initialization with double-checked locking?

有木有妳兜一样 2024-11-14 09:15:15

我对识别为模式特别感兴趣的部分是检查 ->锁->检查。

这称为双重检查锁定

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

The part that I'm especially interested in identifying as a pattern is the check -> lock -> check.

That is called double-checked locking.

Beware that in older Java versions (before Java 5) it is not safe because of how Java's memory model was defined. In Java 5 and newer changes were made to the specification of Java's memory model so that it is now safe.

初熏 2024-11-14 09:15:15

对于这种情况,我想到的唯一名称是“故障”。该名称在 iOS Core-Data 框架中使用,具有类似的效果。

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

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

The only name that comes to mind for this kind of is "Faulting". This name is used in iOS Core-Data framework to similar effect.

Basically, your method NameDoesNotMatter is a fault, and whenever someone invokes it, it results in the object to get populated or initialized.

See http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdFaultingUniquing.html for more details on how this design pattern is used.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文