為什么需要單例泌霍?
- 節(jié)省內(nèi)存和計(jì)算货抄,
- 保證結(jié)果正確
- 方便管理
適用場(chǎng)景
- 無狀態(tài)的工具類:比如日志工具
- 全局信息類
八種寫法
1. 餓漢式(靜態(tài)常量)[可用]
public class Singleton1 {
//類加載的時(shí)候完成了實(shí)例化,對(duì)象就被創(chuàng)建初始化
private final static Singleton1 INSTANCE = new Singleton1();
//單例的構(gòu)造都是私有的
private Singleton1() {
}
public static Singleton1 getInstance() {
return INSTANCE;
}
}
2. 餓漢式(靜態(tài)代碼塊)[可用]
public class Singleton2 {
private final static Singleton2 INSTANCE;
//只是將初始化的工作放在了靜態(tài)塊里朱转,歸根結(jié)底是一樣的蟹地,都是在類加載的時(shí)候完成了初始化
static {
INSTANCE = new Singleton2();
}
private Singleton2() {
}
public static Singleton2 getInstance() {
return INSTANCE;
}
}
3. 懶漢式(線程不安全)[不可用]
public class Singleton3 {
private static Singleton3 instance;
private Singleton3() {
}
public static Singleton3 getInstance() {
if (instance == null) {
instance = new Singleton3();
}
return instance;
}
}
4. 懶漢式(線程安全,同步方法)[不推薦用]
public class Singleton4 {
private static Singleton4 instance;
private Singleton4() {
}
public synchronized static Singleton4 getInstance() {
if (instance == null) {
instance = new Singleton4();
}
return instance;
}
}
5. 懶漢式(線程不安全藤为,同步代碼塊)[不可用]
public class Singleton5 {
private static Singleton5 instance;
private Singleton5() {
}
public static Singleton5 getInstance() {
if (instance == null) {
synchronized (Singleton5.class) {
instance = new Singleton5();
}
}
return instance;
}
}
6. 懶漢式(雙重檢查) [推薦用]
- 優(yōu)點(diǎn):線程安全怪与,延遲加載, 效率較高
- 為什么要double-check?
線程安全
單check行不行缅疟?
性能問題 - 為什么要用volatile分别?
- 新建對(duì)象實(shí)際上有3個(gè)步驟,分配對(duì)象空間創(chuàng)建一個(gè)對(duì)象->然后執(zhí)行構(gòu)造方法初始化對(duì)象->然后把地址賦值給引用存淫,但是jvm和CPU可能會(huì)對(duì)這個(gè)過程重排序耘斩,導(dǎo)致,分配完對(duì)象的內(nèi)存空間纫雁,就賦值給引用煌往,這個(gè)時(shí)候如果還沒完成初始化,其他的線程拿到這個(gè)對(duì)象進(jìn)行操作就可能導(dǎo)致空指針異常轧邪。所以使用volatile可以禁止指令重排序避免這個(gè)問題刽脖,線程在任何時(shí)候取得的對(duì)象都是初始化完成的,就不會(huì)發(fā)生空指針忌愚。
public class Singleton6 {
private volatile static Singleton6 instance;
private Singleton6() {
}
public static Singleton6 getInstance() {
if (instance == null) {
synchronized (Singleton6.class) {
if (instance == null) {
instance = new Singleton6();
}
}
}
return instance;
}
}
7. 靜態(tài)內(nèi)部類[推薦用]
可以認(rèn)為是懶漢的一種
public class Singleton7 {
private Singleton7() {
}
private static class SingletonInstance {
//static 的屬性只在類加載的時(shí)候初始化一次
private static final Singleton7 INSTANCE = new Singleton7();
}
public static Singleton7 getInstance() {
//方法走到這里曲管,觸發(fā)加載SingletonInstance.class,從而初始化INSTANCE
return SingletonInstance.INSTANCE;
}
}
8. 枚舉[推薦用]
枚舉要少用硕糊,但是枚舉單例可以用院水,因?yàn)橹挥幸粋€(gè)對(duì)象
public enum Singleton8 {
INSTANCE;
public void whatever() {
}
}