餓漢式
提前new出來實例了,並不是在第一次調用get方法時才實例化,沒有進行延遲加載
public class Singleton1 {
private static Singleton1 instance = new Singleton1();
private Singleton1(){}
public static Singleton1 getInstance(){
return instance;
}
}
懶漢式——非線程安全版本
多線程環境下無法保證單例效果,會多次執行 instance=new Singleton(),需要考慮到多線程
public class Singleton2 {
private static Singleton2 instance;
private Singleton2(){}
public static Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
}
return instance;
}
}
懶漢式——同步代碼塊版
性能不高,同步范圍太大,在實例化instacne后,獲取實例仍然是同步的,效率太低,需要縮小同步的范圍。
public class Singleton3 {
private static Singleton3 instance;
private Singleton3(){}
public static synchronized Singleton3 getInstance(){
if(instance == null){
instance = new Singleton3();
}
return instance;
}
}
懶漢式——同步方法一層check版
縮小同步范圍,來提高性能,但是讓然存在多次執行instance=new Singleton()的可能,由此引出double check
https://www.jianshu.com/p/d53bf830fa09
方法:
- 實例方法,鎖住的是實例,public synchronized void method()
- 靜態方法,鎖住的是類,public static synchronized void method()
代碼塊:
- 實例對象,鎖住的是實例對象,synchronized(this){}
- class對象,鎖住的是類對象,synchronized(xxx.class){}
- 任意對象, 實例對象的Object,string ss; synchronized(ss){}
public class Singleton4 {
private static Singleton4 instance;
private Singleton4(){}
public static Singleton4 getInstance(){
if(instance == null){
synchronized (instance){
instance = new Singleton4();
}
}
return instance;
}
}
懶漢式——double check版
避免的上面方式的明顯缺點,但是java內存模型(jmm)並不限制處理器重排序,在執行instance=new Singleton();時,並不是原子語句。
public class Singleton5 {
private static Singleton5 instance;
private Singleton5(){}
public static Singleton5 getInstance(){
if(instance == null){
synchronized (instance){
if(instance == null){
instance = new Singleton5();
}
}
}
return instance;
}
}
終極版——volatile防指令重排避免多線程出錯
創建一個對象,實際是包括了下面三大步驟:
- 為對象分配內存
- 初始化實例對象
- 把引用instance指向分配的內存空間
這個三個步驟並不能保證按序執行,處理器會進行指令重排序優化,存在這樣的情況:優化重排后執行順序為:1,3,2, 這樣在線程1執行到3時,instance已經不為null了,線程2此時判斷instance!=null,則直接返回instance引用,但現在實例對象還沒有初始化完畢,此時線程2使用instance可能會造成程序崩潰。
public class Singleton6 {
private static volatile Singleton6 instance;
private Singleton6(){}
public static Singleton6 getInstance(){
if(instance == null){
synchronized (instance){
if(instance == null){
instance = new Singleton6();
}
}
}
return instance;
}
}
懶漢式——靜態內部類
靜態內部類實現的懶漢式.
靜態部分依賴於類,而不是對象,因此會優先於對象加載。類執行的順序:
- 靜態屬性、靜態方法聲明、靜態塊
- 動態屬性、普通方法聲明、普通代碼塊
- 構造方法
public class Singleton7 {
private Singleton7(){}
public static Singleton7 getInstance(){
return InstanceHolder.instance;
}
static class InstanceHolder{
private static Singleton7 instance = new Singleton7();
}
}