Java基礎系列-單例的7種寫法

唯一浩哥發表於2020-11-06

原創文章,轉載請標註出處:https://www.cnblogs.com/V1haoge/p/10755322.html

一、概述

Java中單例有7種寫法,這個是在面試中經常被問到的內容,而且有時候還要求手寫單例實現方式。所以我們有必要認真的瞭解一下這七種寫法。

二、七種實現

2.1 懶漢式——執行緒不安全

public class SingletonOne {
    public static SingletonOne singleton;
    private SingletonOne() {}
    public static SingletonOne getSingleton() {
        if (singleton == null)
            return new SingletonOne();
        return singleton;
    }
}

懶漢式實現了懶載入,但是執行緒不安全,基本不會使用。

2.2 懶漢式——執行緒安全

public class SingletonTwo {
    public static SingletonTwo singleton;
    private SingletonTwo() {}
    public static synchronized SingletonTwo getSingleton() {
        if (singleton == null)
            return new SingletonTwo();
        return singleton;
    }
}

在第一種的基礎上加了個synchronized,保證執行緒安全,同時實現了懶載入,只是效率不高。

2.3 餓漢式

public class SingletonThree {
    public static SingletonThree singleton = new SingletonThree();
    private SingletonThree () { }
    public static SingletonThree getSingleton() {
        return singleton;
    }
}

由於例項優先提供,不存線上程安全問題,但是沒有實現懶載入。

2.4 餓漢式——變種

public class SingletonFour {
    public static SingletonFour singleton;
    static {
        singleton = new SingletonFour();
    }
    private SingletonFour () { }
    public static SingletonFour getSingleton() {
        return singleton;
    }
}

其實和之前的一樣,僅僅是將單例的建立挪到了靜態塊。

2.5 靜態內部類式

public class SingletonFive {
    private static class SingletonHolder {
        private static SingletonFive singleton = new SingletonFive();
    }
    private SingletonFive () {}
    public static final SingletonFive getSingleton(){
        return SingletonHolder.singleton;
    }
}

靜態內部類保證了懶載入,單例例項優先提供又保證了執行緒安全性,較實用。

2.6 列舉式

public enum SingletonSix {
    SINGLETON;
}

列舉的天然特性保證了單例,天然的私有構造器,天然的執行緒安全性,未被大規模使用的原因是列舉出現的有點晚。

2.7 雙重校驗鎖式

public class SingletonSeven {
    private static volatile SingletonSeven singleton;
    private SingletonSeven() {}
    public static SingletonSeven getSingleton(){
        if (singleton == null) {
            synchronized (SingletonSeven.class) {
                if (singleton == null)
                    return new SingletonSeven();

            }
        }
        return singleton;
    }
}

注意:

  1. volatile的使用,為了防止暴露一個未初始化的不完整單例例項;
  2. 雙重判空校驗,第一個判斷避免了頻繁的加鎖,第二個判斷可以攔住多餘的建立例項的執行緒;
  3. 加鎖,保證了執行緒安全(只有一個例項)

這種實現方式是經常出現在面試題中的,而且經常會要求手寫。

三、總結

上面羅列的7種設計模式中第1種執行緒不安全,可以排除在外,第3、4種其實是一種,這樣下來其實可以簡化為5種方式:懶漢、餓漢、靜態內部類、列舉、雙重校驗鎖。

相關文章