#双重检查锁定问题private static SomeClass instance; public SomeClass getInstance() { if (null == instance) { // 第一重检查 synchronized (this) { if (null == instance) { // 第二重检查 instance = new SomeClass(); // 这里有问题 } } } return instance; } 这样写的话,运行顺序就成了: 检查变量是否被初始化(不去获得锁),如果已被初始化立即返回这个变量。 获取锁 第二次检查变量是否已经被初始化:如果其他线程曾获取过锁,那么变量已被初始化,返回初始化的变量。否则,初始化并返回变量。 这样,除了初始化的时候会出现加锁的情况,后续的所有调用都会避免加锁而直接返回,从而避免了性能问题,而且看似也解决了同步的问题,然而这样写有个很大的隐患。详细原因如下: 实例化对象的那行代码(标记为有问题的那行),实际上可以分解成以下三个步骤: 分配内存空间 初始化对象 将对象指向刚分配的内存空间 但是有些编译器为了性能的原因,可能会将第二步和第三步进行重排序,顺序就成了: 分配内存空间 将对象指向刚分配的内存空间 初始化对象 现在考虑重排序后,发生了以下这种调用: Time Thread A Thread B t1 A1 检查到instance为空 t2 A2 获取锁 t3 A3 再次检查到instance为空 t4 A4 为instance分配内存空间 t5 A5 将instance指向内存空间 t6 B1 检查到instance不为空 t7 B2 访问instance(对象还未初始化) t8 A6 初始化instance 注意,在这种情况下,t7时刻线程B对instance的访问,访问的是一个初始化未完成的对象! 解决: private volatile static SomeClass instance; 但一般用 内部静态类方式 | enum单例方式