同事最近在编写Cache Server的Hash算法的时候,碰到了多核心CPU的问题。查了一些资料,这里有一些经验和大家分享:
我们常常使用单例模式创建一个可以被多线程共享的对象。传统的方法是使用一个static变量或者使用double check+lock手工处理单例。但是在进入了多核、64位时代后,就不在那么简单了。尤其是IA64(安腾64结构,服务器CPU,非笔记本和台式机的CPU)的内存是弱内存模型(执行Memory Reordering的策略, 弱类型表示不会严格按照程序语句的执行顺序执行)。
也就是说,即使使用了“多线程安全”的static变量和“Double Lock”模式,在IA64上仍然会出现创建两次单例的情况。下面的语句仍然存在会创建两次实例的可能:
public class Singleton
{
private static object syncRoot = new object();
private Singleton instance;
private Singleton() { }
public Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
解决办法是使用改进的单例模式:
public class Singleton
{
private static object syncRoot = new object();
private volatile Singleton instance;
private Singleton() { }
public Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
Singleton singleObj = new Singleton();
System.Threading.Thread.MemoryBarrier();
instance = singleObj;
}
}
}
return instance;
}
}
如果想知道这么做具体的技术细节,可以查看相关的资料。否则请记住结论,因为单例是我们常常使用的设计模式,所以希望以后大家都使用上面的方式创建单例,可以避免遇到多核CPU的问题。