前几天看见一贴:http://community.csdn.net/Expert/topic/5077/5077652.xml?temp=.73901
由此想到,lock字符串对象是种不适合的行为。
针对字符串,根据string的恒定性,.NET有个拘留池,用来提高性能。
[MSDN]
公共语言运行库通过维护一个表来存放字符串,该表称为拘留池,它包含程序中以编程方式声明或创建的每个唯一的字符串的一个引用。因此,具有特定值的字符串的实例在系统中只有一个。
例如,如果将同一字符串分配给几个变量,运行库就会从拘留池中检索对该字符串的相同引用,并将它分配给各个变量。
由于这个原因,假如你lock的字符串对象在拘留池中(通常是编译时显式声明的用引号引起来的字符串),那么,这个对象也有可能被分配到另外一个变量,如果这个变量也使用了lock,那么,两个lock语句表面上lock的不同对象,但实质上却是同一个对象,这将造成不必要的阻塞,甚至可能造成死锁。且不亦发现问题。
但是,只要你的字符串对象不是在拘留池中,则不会出现这个问题。
若lock时还要先观察是否在拘留池,这有点费神。所以,建议不要lock字符串对象。
示例:
//表面上,这两段代码没任何关系。但假如Do1刚好执行完lock(str1)准备执行lock(stra)而另一线程
//Do2刚好执行完lock(strB)正准备执行lock(str2),那么这两个线程将永远等待对方造成线程死锁。
static string str1 = "";
static string strA = "good";
void Do1()
{
lock (str1)
{
lock (strA)
{
System.Threading.Thread.Sleep(1000 * 10);
}
}
}
static string str2 = "";
static string strB = "good";
void Do2()
{
lock (strB)
{
lock (str2)
{
System.Threading.Thread.Sleep(1000 * 10);
}
}
}
//Do2刚好执行完lock(strB)正准备执行lock(str2),那么这两个线程将永远等待对方造成线程死锁。
static string str1 = "";
static string strA = "good";
void Do1()
{
lock (str1)
{
lock (strA)
{
System.Threading.Thread.Sleep(1000 * 10);
}
}
}
static string str2 = "";
static string strB = "good";
void Do2()
{
lock (strB)
{
lock (str2)
{
System.Threading.Thread.Sleep(1000 * 10);
}
}
}