在本文中,我们将带你了解Java为什么在双重检查锁定中使用了volatile在这篇文章中,我们将为您详细介绍Java为什么在双重检查锁定中使用了volatile的方方面面,并解答java双重检查锁的问
在本文中,我们将带你了解Java 为什么在双重检查锁定中使用了volatile在这篇文章中,我们将为您详细介绍Java 为什么在双重检查锁定中使用了volatile的方方面面,并解答java双重检查锁的问题常见的疑惑,同时我们还将给您一些技巧,以帮助您实现更有效的.NET中双重检查锁定中对volatile修饰符的需求、c# – 为什么表达式总是为’双重检查锁定’?、c# – 为什么这个双重检查锁定正确? (.净)、c# – 使用双重检查锁定的内存读取可见性排序与写入顺序。
本文目录一览:- Java 为什么在双重检查锁定中使用了volatile(java双重检查锁的问题)
- .NET中双重检查锁定中对volatile修饰符的需求
- c# – 为什么表达式总是为’双重检查锁定’?
- c# – 为什么这个双重检查锁定正确? (.净)
- c# – 使用双重检查锁定的内存读取可见性排序与写入顺序
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
在完成构造之前为其分配存储空间instance
。Thread B
将看到该作业并尝试使用它。Thread B
由于使用的是的部分构造版本,因此导致失败instance
。
.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# – 为什么表达式总是为’双重检查锁定’?
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 6.0中修复.
顺便说一下,ReSharper 6带来了更多双锁模式分析的东西:)
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.
解决方法
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# – 使用双重检查锁定的内存读取可见性排序与写入顺序
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之前没有释放围栏设置为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 为什么在双重检查锁定中使用了volatile和java双重检查锁的问题的分享已经告一段落,感谢您的关注,如果您想了解更多关于.NET中双重检查锁定中对volatile修饰符的需求、c# – 为什么表达式总是为’双重检查锁定’?、c# – 为什么这个双重检查锁定正确? (.净)、c# – 使用双重检查锁定的内存读取可见性排序与写入顺序的相关信息,请在本站查询。
本文标签: