單例模塊中延時加載/懶漢模式在多線程中的處理

在單例中取得對象通常使用一個靜態方法,如: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();
}
結果:
764787692
1097112149
869295101


處理方法有以下:
案例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;
	}
}
第一種其實與第二種同樣
案例3:
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雙檢查鎖機制
相關文章
相關標籤/搜索