多線程下的單例模式

單例的實現

1.單線程下的Lazy實現

public class Main {
    private static Main instance = null;
    
    private Main() {}
    
    public static Main getInstance() {
        if(null == instance) instance = new Main();
        return instance;
    }
}

2.針對1的多線程阻塞實現

就是改進了check-then-act的原子性問題java

public class Main {
    private static Main instance = null;
    
    private Main() {}
    
    public static Main getInstance() {
        synchronized(Main.class) {
            if(null == instance) instance = new Main();
        }
        return instance;
    }
}

3.錯誤的雙重加鎖

public class Main {
    private static Main instance = null;
    
    private Main() {}
    
    public static Main getInstance() {
        if(null == instance) synchronized(Main.class) {
            if(null == instance) instance = new Main(); // 問題出如今初始化
        }
        return instance;
    }
}

注意可見性是正確的,錯誤在於初始化的重排序多線程

上一篇文章已經寫了3個步驟,一個線程在判斷第一個if的時候可能另外一個線程執行到第二個步驟就寫入引用了,這時返回的是默認值線程

4.正確的雙重加鎖

既然重排序有問題那固然要volatilecode

public class Main {
    private static volatile Main instance = null;
    
    private Main() {}
    
    public static Main getInstance() {
        if(null == instance) synchronized(Main.class) {
            if(null == instance) instance = new Main();
        }
        return instance;
    }
}

5.靜態內部類

利用class文件對於內部類的特性,實現上夠簡單排序

public class Main {
    
    private static class InstanceHolder {
        final static Main INSTANCE = new Main();
    }
    
    public static Main getInstance() {
        return InstanceHolder.INSTANCE;
    }
}

6.枚舉類

僅訪問Singleton自己不會使Singleton.INSTANCE初始化內存

public enum Singleton {
    INSTANCE;
    Singleton() {}
    public void doSomething() {}
}

public class Main {
    public static void main() {
        new Thread() {
            public void run() {
                Singleton.INSTANCE.doSomething();
            }
        }.start();
    }
    
}

懶漢?餓漢?

補充一下奇怪的術語:懶漢式、餓漢式get

其中懶漢式就是帶Lazy加載的意思,好比一、2class

而餓漢式我並不太清楚字面上的意思。。應該是指內存寬裕吧。。就是static直接返回的那種,顯然不如靜態內部類序列化

public class Main {
    private static Main instance = new Main();
    private Main() {}
    public static Main getInstance() { return instance; }
}

破壞單例模式

1.除了enum和靜態內部類,其它均可以被newInstance()拿到手

改進方法就是在構造方法建立保護null的判斷引用

2.還有一種反序列化的破壞方式(若是你的單例須要序列化)。。

解決方法是重寫readResolve()方法,使得它在方法內直接返回instance

相關文章
相關標籤/搜索