在單例中取得對象通常使用一個靜態方法,如:newInstance,instance,...。而方法中有兩種處理,一種是先前就已經建立了一個靜態實例(當即加載/餓漢模式),而另外一種是在調用方法時建立(延時加載/懶漢模式)如: java
public static class MyObject{ private static MyObject instance; public static MyObject newInstance(){ if(instance==null){ //此處可能有多個線程已經進入 instance=new MyObject(); } return instance; } }
但在多線程中就有可能返回不一樣的實例,這違背了單例的原則,如: 多線程
public static class MyObject{ private static MyObject instance; public static MyObject newInstance(){ if(instance==null){ Thread.sleep(3000); //放大延時時間,(這裏應該有異常拋出,爲了簡潔就不加了) instance=new MyObject(); } return instance; } } public static void main(String[] args) { new Thread(){ @Override public void run() { System.out.println(MyObject.newInstance().hashCode()); } }.start(); new Thread(){ @Override public void run() { System.out.println(MyObject.newInstance().hashCode()); } }.start(); new Thread(){ @Override public void run() { System.out.println(MyObject.newInstance().hashCode()); } }.start(); }結果:
處理方法有以下:
案例1:
ide
public static class MyObject{ private static MyObject instance; synchronized public static MyObject newInstance(){ if(instance==null){ //Thread.sleep(3000); instance=new MyObject(); } return instance; } }
案例2: spa
public static class MyObject{ private static MyObject instance; public static MyObject newInstance(){ synchronized(MyObject.class){ if(instance==null){ //Thread.sleep(3000); instance=new MyObject(); } } return instance; } }第一種其實與第二種同樣
public static class MyObject { private static MyObject instance; public static MyObject newInstance() { if (instance == null) { // Thread.sleep(3000); synchronized (MyObject.class) { if (instance == null) { instance = new MyObject(); } } } return instance; } }使用DCL雙檢查鎖機制