GVKun编程网logo

Java 为什么在双重检查锁定中使用了volatile(java双重检查锁的问题)

28

在本文中,我们将带你了解Java为什么在双重检查锁定中使用了volatile在这篇文章中,我们将为您详细介绍Java为什么在双重检查锁定中使用了volatile的方方面面,并解答java双重检查锁的问

在本文中,我们将带你了解Java 为什么在双重检查锁定中使用了volatile在这篇文章中,我们将为您详细介绍Java 为什么在双重检查锁定中使用了volatile的方方面面,并解答java双重检查锁的问题常见的疑惑,同时我们还将给您一些技巧,以帮助您实现更有效的.NET中双重检查锁定中对volatile修饰符的需求、c# – 为什么表达式总是为’双重检查锁定’?、c# – 为什么这个双重检查锁定正确? (.净)、c# – 使用双重检查锁定的内存读取可见性排序与写入顺序

本文目录一览:

Java 为什么在双重检查锁定中使用了volatile(java双重检查锁的问题)

Java 为什么在双重检查锁定中使用了volatile(java双重检查锁的问题)

Head First设计模式手册中,具有双重检查锁定的单例模式已实现如下:

public class Singleton {    private volatile static Singleton instance;    private Singleton() {}    public static Singleton getInstance() {        if (instance == null) {            synchronized (Singleton.class) {                if (instance == null) {                    instance = new Singleton();                }            }        }        return instance;    }}

我不明白为什么volatile要使用它。volatile使用不会 违反使用双重检查锁定(即性能)的目的吗?

答案1

小编典典

真正的问题是Thread A可能instance在完成构造之前为其分配存储空间instanceThread B将看到该作业并尝试使用它。Thread B由于使用的是的部分构造版本,因此导致失败instance

.NET中双重检查锁定中对volatile修饰符的需求

.NET中双重检查锁定中对volatile修饰符的需求

多篇文章说,在.NET中实施双重检查锁定时,您要锁定的字段应应用volatile修饰符。但是为什么呢?考虑以下示例:

public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null) 
         {
            lock (syncRoot) 
            {
               if (instance == null) 
                  instance = new Singleton();
            }
         }

         return instance;
      }
   }
}

为什么“锁(syncRoot)”无法实现必要的内存一致性?在“锁定”语句之后读取和写入都是不稳定的,这样就可以实现必要的一致性,这不是真的吗?

c# – 为什么表达式总是为’双重检查锁定’?

c# – 为什么表达式总是为’双重检查锁定’?

我有单独的对象’服务’和两个初始化和释放它的方法:
public class BaseService
{
    protected static readonly object StaticLockObject = new object();
}

public abstract class WebServiceBase<TService> : BaseService
    where TService : System.Web.Services.Protocols.soapHttpClientProtocol,new()
{
    protected static void EnsureServiceIsOpened()
    {
        if (Service == null)
        {
            lock (StaticLockObject)
            {
                if (Service == null)
                {
                    Service = new TService();
                }
            }
        }
    }

    protected static void EnsureServiceIsClosed()
    {
        if (Service != null)
        {
            lock (StaticLockObject)
            {
                if (Service != null) // Why expression is always true
                {
                    Service.dispose();
                    Service = null;
                }
            }
        }
    }

对于带注释resharper的行(我使用版本5.1)显示一个提到的警告…

问题1:为什么?

问题2:为什么它不在’EnsureServiceIsOpened’方法中显示“类似”消息?

谢谢.

解决方法

这是ReSharper 5.X代码分析引擎中的错误.
在ReSharper 6.0中修复.

顺便说一下,R​​eSharper 6带来了更多双锁模式分析的东西:)

c# – 为什么这个双重检查锁定正确? (.净)

c# – 为什么这个双重检查锁定正确? (.净)

我已经阅读了很多关于双重检查锁定的危险,我会努力远离它,但据说,我认为它们是一个非常有趣的阅读.

我正在阅读Joe Duffy关于使用双重检查锁定实现单例的这篇文章:
http://www.bluebytesoftware.com/blog/PermaLink,543d89ad-8d57-4a51-b7c9-a821e3992bf6.aspx

他似乎提出的(变体)解决方案是这样的:

class Singleton {
private static object slock = new object();
private static Singleton instance;
private static int initialized;
private Singleton() {}
public Instance {
    get {
        if (Thread.VolatileRead(ref initialized) == 0) {
            lock (slock) {
                if (initialized == 0) {
                    instance = new Singleton();
                    initialized = 1;
                }
            }
        }
        return instance;
    }
}

}

我的问题是,是否仍然存在写入重新排序的危险?具体来说这两行:

instance = new Singleton();
initialized = 1;

如果这些写入被反转,那么其他一些线程仍然可以读取null.

解决方法

我认为关键在于链接文章( http://msdn.microsoft.com/en-us/magazine/cc163715.aspx#S5).具体来说,MS实现的.NET 2.0内存模型具有以下属性:

Writes cannot move past other writes from the same thread.

Duffy提到在IA-64上做了很多工作来支持这个:

We accomplish this by ensuring writes have ‘release’ semantics on IA-64,via the st.rel instruction. A single st.rel x guarantees that any other loads and stores leading up to its execution (in the physical instruction stream) must have appeared to have occurred to each logical processor at least by the time x’s new value becomes visible to another logical processor. Loads can be given ‘acquire’ semantics (via the ld.acq instruction),meaning that any other loads and stores that occur after a ld.acq x cannot appear to have occurred prior to the load.

请注意,Duffy还提到这是MS特定的保证 – 它不是ECMA规范的一部分(至少在2006年的文章撰写时).所以,Mono可能不那么好.

c# – 使用双重检查锁定的内存读取可见性排序与写入顺序

c# – 使用双重检查锁定的内存读取可见性排序与写入顺序

我有以下函数,旨在“memoize”无参数函数.意思是只调用一次函数,然后在其他时间返回相同的结果.
private static Func<T> Memoize<T>(Func<T> func)
{
    var lockObject = new object();
    var value = default(T);
    var inited = false;

    return () => {
        if (inited)
            return value;

        lock (lockObject) {
            if (!inited) {
                value = func();
                inited = true;
            }
        }

        return value;
    };
}

我可以确定如果一个线程在锁外读取“inited == true”,那么它将读取在“inited”设置为true之前写入的“值”吗?

注意:Double-checked locking in .NET涵盖了它应该工作的事实,这个问题主要是检查我的实现是否正确并且可能获得更好的替代方案.

解决方法

不,因为inited不易变. volatile为您提供内存释放并获取您需要的围栏,以便建立正确的先发生关系.

如果在inited之前没有释放围栏设置为true,那么在另一个线程读入并且将其视为真时,该值可能不会完全写入,这可能导致返回半构造的对象.类似地,如果在第一次检查中读取之前有一个释放围栏但没有相应的获取围栏,那么该对象可能是完全构造的,但是看作真实的cpu核心还没有看到值的记忆效应写入(缓存一致性并不一定要求在其他核心上按顺序看到连续写入的影响).这将再次潜在地导致返回半构造的对象.

顺便说一句,这是已经非常详细记录的双重检查锁定模式的实例.

我建议不要使用捕获局部变量的lambda(这会使编译器生成一个隐式类来保存非易失性字段中的闭合变量),而是建议使用volatile属性值明确创建自己的类.

private class Memoized<T>
{
    public T value;
    public volatile bool inited;
}

private static Func<T> Memoize<T>(Func<T> func)
{
    var memoized = new Memoized<T>();

    return () => {
        if (memoized.inited)
            return memoized.value;

        lock (memoized) {
            if (!memoized.inited) {
                memoized.value = func();
                memoized.inited = true;
            }
        }

        return memoized.value;
    };
}

当然,正如其他人提到的Lazy< T>.为此目的而存在.使用它而不是自己动手,但了解事物如何运作的理论总是一个好主意.

我们今天的关于Java 为什么在双重检查锁定中使用了volatilejava双重检查锁的问题的分享已经告一段落,感谢您的关注,如果您想了解更多关于.NET中双重检查锁定中对volatile修饰符的需求、c# – 为什么表达式总是为’双重检查锁定’?、c# – 为什么这个双重检查锁定正确? (.净)、c# – 使用双重检查锁定的内存读取可见性排序与写入顺序的相关信息,请在本站查询。

本文标签: