我已经阅读了所有关于双重检查锁定修复程序永远不会工作的所有内容,我不喜欢延迟初始化,但是能够修复遗留代码并且这样的问题太诱人而不试图解决会很好.
这是我的例子:
private int timesSafelyGotten = 0;
private Helper helper = null;
public getHelper()
{
if (timesSafelyGotten < 1) {
synchronized (this) {
if (helper == null) {
helper = new Helper();
} else {
timesSafelyGotten++;
}
}
}
return helper;
}
这样,同步代码必须运行一次以创建帮助程序,并且一旦第一次获得帮助程序,理论上,在创建帮助程序的同步代码释放锁并且辅助程序必须完成初始化之后,理论上,timesSafelyGotten才能递增.
我没有看到任何问题,但这很简单,看起来好得令人难以置信,您怎么看?
Caleb James DeLisle
解决方法:
如果没有内存屏障(来自java.util.concurrent的同步,易失性或等效),则线程可能会看到另一个线程的操作的顺序与它们在源代码中出现的顺序不同.
由于在timesSafelyGotten的读取上没有内存障碍,因此在另一个线程中可以看到timesSafelyGotten在分配helper之前递增.这将导致从方法返回null.
实际上,在单元测试期间,这可能适用于许多体系结构.但这不正确,最终会在某个地方失败.
双重检查锁定现在可以正常工作,但实现正确且相当昂贵是很棘手的.延迟初始化的模式不那么脆弱,更易读,并且不需要任何异国情调.