一、餓漢式
此方式的關鍵在於instance作爲類變量並且直接得到了初始化
public class SingletonObject1 {
private static final SingletonObject1 instance=new SingletonObject1();
public static SingletonObject1 getInstance(){
return instance;
}
}
缺點: 不能懶加載(佔用內存)
二、懶漢式
懶漢式就是使用類實例的時候再去創建,避免出現類在初始化的時候提前創建
public class SingletonObject2 {
// 定義實例,但不進行初始化
private static SingletonObject2 intance;
public static SingletonObject2 getInstance(){
if (null==intance){
intance= new SingletonObject2();
}
return SingletonObject2.intance;
}
}
缺點: 懶漢式可以保證實例的懶加載,但是無法保證實例的唯一性。
三、懶漢式+同步方法
在多線程的情況下,多個線程同時訪問instance(共享資源)需要保證數據的一致性,增加同步的約束。
public class SingletonObject3 {
// 定義實例,但不進行初始化
private static SingletonObject3 intance;
// 向getInstance方法加入同步控制,每次只能有一個線程能夠進入
public synchronized static SingletonObject3 getInstance(){
if (null==intance){
intance= new SingletonObject3();
}
return SingletonObject3.intance;
}
}
缺點:儘管synchornized已經進行了優化,但是此關鍵字依舊導致getInstance方法只能在同一時刻被一個線程訪問,降低了性能。
四、Double-Check
此種方式提供了一種高效的數據同步策略,就是首次初始化時加鎖。
public class SingletonObject6 {
// 定義實例,但不進行初始化
private static SingletonObject6 instance;
public static SingletonObject6 getInstance(){
// 當instance爲null的時候,進入代碼塊,同時判讀那避免每次都需要進入同步代碼塊,可以提高效率
if (null==instance){
synchronized (SingletonObject6.class){
// 判斷instance是否被創建
if(null==instance){
instance=new SingletonObject6();
}
}
}
return SingletonObject6.instance;
}
}
缺點:在多線程的情況下可能會引起空指針異常
五、volatile+Double-Check
加入volatile關鍵字防止jvm在運行時指令重排序
public class SingletonObject5 {
// 定義實例,但不進行初始化,加volatile使其對象可見
private volatile static SingletonObject5 instance;
public static SingletonObject5 getInstance(){
// 當instance爲null的時候,進入代碼塊,同時判讀那避免每次都需要進入同步代碼塊,可以提高效率
if (null==instance){
synchronized (SingletonObject5.class){
// 判斷instance是否被創建
if(null==instance){
instance=new SingletonObject5();
}
}
}
return SingletonObject5.instance;
}
}
六、靜態內部類的方式
藉助類加載的特點,對單例進行重構。在Singleton類中沒有instance的靜態成員,而是將其放到了靜態內部類中,以保證在Singleton類初始化過程中不會創建Singleton的實例,在靜態內部類中定了singleton的靜態變量,並且直接進行了初始化。
public class SingletonObject3 {
// 在靜態內部類中喫有Singleton的實例,並且可以被直接初始化
private static class InstanceHolder{
private static SingletonObject3 instance=new SingletonObject3();
}
// 調用getInstance方法,事實上是獲得靜態內部類的instance靜態屬性
public static SingletonObject3 getInstance(){
return InstanceHolder.instance;
}
}
七、枚舉的方式
推薦使用的一種方式,枚舉類型不允許被繼承,同樣是線程安全的且只能被實例化一次,但是枚舉類型不能進行懶加載,對Singleton主動使用。
public class SingletonObject4 {
// 枚舉本身就是final的,不允許被繼承
private enum EnumSingleton{
// 實例變量
INSTSNCE;
private SingletonObject4 instance;
EnumSingleton(){
this.instance=new SingletonObject4();
}
public SingletonObject4 getInstance(){
return instance;
}
}
public static SingletonObject4 getInstance(){
return EnumSingleton.INSTSNCE.getInstance();
}
}