在MSDN文档说,
public class SomeObject
{
public void SomeOperation()
{
lock(this)
{
//Access instance variables
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果可以公开访问实例,那就是"一个问题".我想知道为什么?是因为锁定的持有时间超过了必要的时间吗?还是有一些更阴险的原因?
这来自MSDN:lock关键字确保一个线程不进入代码的关键部分,而另一个线程处于临界区.
难道一个关键部分必须是相同的关键部分?
或者它的意思是:lock关键字确保一个线程不会进入由代码对象保护的任何关键部分,而另一个线程处于由同一对象保护的任何关键部分.?
class Program
{
static void Main(string[] args)
{
TestDifferentCriticalSections();
Console.ReadLine();
}
private static void TestDifferentCriticalSections()
{
Test lo = new Test();
Thread t1 = new Thread(() =>
{
lo.MethodA();
});
t1.Start();
Thread t2 = new Thread(() =>
{
lo.MethodB();
});
t2.Start();
}
}
public class Test
{
private object obj = new object();
public Test()
{ }
public void MethodA()
{
lock (obj) …Run Code Online (Sandbox Code Playgroud) 在Java程序员中众所周知,为了使双重检查锁定正常运行,必须声明变量volatile,并且同步对象的初始化是不够的.
意识可能主要是因为volatile关键字的语义在1.5中改变为包括"之前发生"关系,至少部分是为了使双重检查锁定安全; 根据我的理解,"发生在之前"关系意味着写入volatile变量会导致线程中的所有缓存变量被写入主内存,并且在从volatile变量读取后,所有缓存变量都被认为是陈旧的,并且必须是从主内存重新读取,以便在写入volatile变量之前写入的所有内容都保证在"稍后从该变量读取之前"发生.
Stack Overflow 似乎认为,对于C#来说,volatile双重检查锁定是不必要的(尽管有人担心这可能是特定于某些CPU或微软的实现),同时也认为Java synchronized语句的语义与 C#的语义完全相同lock声明,这表明在C#中也存在Java中发现的相同问题,除非在两种语言之间的双重检查锁定的语义中存在一些其他主要差异.
那么......哪个是正确的?C#中的双重检查锁定实际上比Java更危险吗?如果是这样,那么语言语义有何不同呢?
如果不是,没有具体可能出错的是volatile什么?volatileC#中的语义是否像Java一样建立了"发生在之前"的关系,因此双重检查锁定在C#中是安全的,volatile因为它在Java中是1.5?
框架:.net 4.5
我使用下面的示例代码模式以线程安全的方式初始化变量.最近我一直在阅读一些文章,这些文章解释了"在某些平台上已经破坏了双重检查锁定http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html "但看起来对我来说没问题.我正在使用.net 4.5.
根据评论提出建议
建议使用lazy并让.net框架在处理基于平台的线程安全和内存模型上做大量工作:):http://msdn.microsoft.com/en-us/library/dd642331.aspx
更新
似乎Eric Lippert一直建议不要使用这种模式(现在很困惑:() 这种模式的名称?(答案:使用双重检查锁定进行延迟初始化) C#手动锁定/解锁
更新2
下面的摘录是"像所有删除读锁的技术一样,图7中的代码(类似于我的代码)依赖于强写入顺序.例如,这个代码在ECMA内存模型中是不正确的,除非myValue变得易失,因为初始化LazyInitClass实例的写入可能会延迟到写入myValue之后,允许GetValue的客户端读取未初始化的状态.在.NET Framework 2.0模型中,代码在没有volatile声明的情况下工作.来自http://msdn.microsoft.com/en-us/magazine/cc163715.aspx
而且我也没有使用'volatile',因为许多示例都显示在不同的代码片段中.我也假设它也可以(参考:.NET中双重检查锁定需要volatile修饰符)
****psudeo代码 - 它解释了我正在使用的版本 - 构建于.net 4.5****之上
static private object s_syncObject = new object();
private static string s_lazyInitializedVariable = null;
//is it necessar to make the backing varible volatie?
//private static volatile string s_lazyInitializedVariable = null;
private static string LazyInitializedVariable
{
get
{
if(string.IsNullOrWhiteSpace(s_lazyInitializedVariable))
{
lock(s_syncObject)
{
if (string.IsNullOrWhiteSpace(s_lazyInitializedVariable))
{
/*
* my …Run Code Online (Sandbox Code Playgroud) 这是避免双重检查锁的有效且优化的方法:
public class SomeBaseClass
{
protected static object InitializeLock = new object();
protected static bool IsInitialized = false;
public void SomeFunction()
{
if (!IsInitialized)
{
System.Threading.Thread.MemoryBarrier();
lock (InitializeLock)
{
// do init stuff
IsInitialized = true;
}
}
//Do stuff that have to happen when function is called
}
}
Run Code Online (Sandbox Code Playgroud)
这是双重检查的选择:
public class SomeBaseClass
{
protected static object InitializeLock = new object();
protected static bool IsInitialized = false;
public void SomeFunction()
{
if (!IsInitialized)
{
lock (InitializeLock)
{
if (!IsInitialized) …Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
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.
} …Run Code Online (Sandbox Code Playgroud)