多線程下的單例模式


單例的實現

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的原子性問題

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.正確的雙重加鎖

既然重排序有問題那當然要volatile

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();
    }
    
}

懶漢?餓漢?

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

其中懶漢式就是帶Lazy加載的意思,比如1、2

而餓漢式我並不太清楚字面上的意思。。應該是指內存寬裕吧。。就是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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM