1使用DCL多线程延迟加载,可能会出现极端的异常问题。
如:
Class Foo
{
Private Resource res = null;
Public Resource getResource()
{
If (res == null)
{
//只有在第一次初始化时,才使用同步方式.
synchronized(this)
{
if(res == null)
{
res = new Resource();
}
}
}
return res;
}
}
解析如下:
Double-Checked Locking看起来是非常完美的。但是很遗憾,根据Java的语言规范,上面的代码是不可靠的。
出现上述问题, 最重要的2个原因如下:
①, 编译器优化了程序指令, 以加快cpu处理速度.
②, 多核cpu动态调整指令顺序, 以加快并行运算能力.
问题出现的顺序:
①, 线程A, 发现对象未实例化, 准备开始实例化
②, 由于编译器优化了程序指令, 允许对象在构造函数未调用完前, 将 共享变量的引用指向 部分构造的对象, 虽然对象未完全实例化, 但已经不为null了.
③, 线程B, 发现部分构造的对象已不是null, 则直接返回了该对象.
替代方案:
public class Foo { private static class LazyFoo { public static Foo foo = new Foo(); } public static Foo getInstance() { return LazyFoo.foo; } }
采用静态内部类实现替换方案,只有当访问到Foo的getInstance方法时,才会初始化foo此static对象。
另外,尽量在程序中少用static变量,因为在部分垃圾回收算法中,静态Field将直接进入堆内存的permanent代,永远不会被回收。
原文地址:http://cmsky.yingjiawujin.com/?p=106