class Single { private Single() { System.out.println("ok"); } private static Single instance = new Single(); public static Single getInstance() { return instance; } }
public class LazySingleton { private static LazySingleton instance; private LazySingleton() {} public static LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } }
public class LazySingleton { private static LazySingleton instance; private LazySingleton() {} public static synchronized LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } }
public class LazySingleton { private static LazySingleton instance; private LazySingleton() {} public static LazySingleton getInstance() { if (instance == null) { synchronized(LazySingleton.class) { if (instance == null) { instance = new LazySingleton(); } } } return instance; } }
可是因爲Java編譯器容許處理器亂序執行(指令重排序),上述二、3點的順序是沒法保證的。(意思是可能instance != null時有可能還未真正初始化構造器)。
解決方法是經過將instance定義爲volatile的。(volatile有兩個語義:1. 保證變量的可見性;2. 禁止對該變量的指令重排序)java
class Single { private Single() {} private static class InstanceHolder { private static final Single instance = new Single(); } public static Single getInstance() { return InstanceHolder.instance(); } }
synchronized
block or method exit) of a monitor happens-before every subsequent lock (synchronized
block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor. (線程安全性主要依賴這條規則)volatile
field happens-before every subsequent read of that same field. Writes and reads of volatile
fields have similar memory consistency effects as entering and exiting monitors, but do not entail mutual exclusion locking.start
on a thread happens-before any action in the started thread.join
on that thread.public class LazySingleton { private int someField; private static LazySingleton instance; private LazySingleton() { this.someField = new Random().nextInt(200)+1; // (1) } public static LazySingleton getInstance() { if (instance == null) { // (2) synchronized(LazySingleton.class) { // (3) if (instance == null) { // (4) instance = new LazySingleton(); // (5) } } } return instance; // (6) } public int getSomeField() { return this.someField; // (7) } }