單例模式
餓漢式 DCL懶漢式 探究
餓漢式
私有構造器 程式一上來就創建好物件 導致-> 可能會浪費記憶體
//餓漢式單例,私有構造器
public class Hungry {
//一上來就把這個全部加載可能會浪費記憶體
private byte[] data1 = new byte[1024*1024];
private byte[] data2 = new byte[1024*1024];
private byte[] data3 = new byte[1024*1024];
private byte[] data4 = new byte[1024*1024];
private byte[] data5 = new byte[1024*1024];
private Hungry(){
}
private final static Hungry HUNGRY = new Hungry();//一上來就new
//一上來就把這個物件加載了
public static Hungry getInstance(){
return HUNGRY;
}
}
DCL懶漢式
這樣單例下OK 多執行緒并發有問題
- 分配記憶體空間
- 執行構造方法,初始化物件
- 把這個物件執向這個空間
正常順序 123
真實順序可能是 132
執行緒A沒問題
執行緒B可能有問題
//懶漢式單例
//結論: 道高一尺,魔高一丈
public class LazyMan {
private static boolean swae_qj = false;//四重檢測,加密
//也是私有構造器
private LazyMan(){
//可以在此處解決-反射破壞單例問題,三重檢測
synchronized (LazyMan.class){
if (swae_qj == false){//四重檢測
swae_qj = true;
}else {
throw new RuntimeException("不要試圖使用反射破壞例外");
}
}
// System.out.println(Thread.currentThread().getName() + "ok");
}
private volatile static LazyMan lazyMan;
public static LazyMan getInstance(){
//兩次檢測要加鎖,因為這樣會導致執行緒數量不確定
//雙重檢測鎖模式的 懶漢式單例 DCL懶漢式
if (lazyMan==null){
synchronized (LazyMan.class){
if (lazyMan==null){//lazyman為空在創建
lazyMan = new LazyMan();//不是一個原子性操作
/**
* 1. 分配記憶體空間
* 2. 執行構造方法,初始化物件
* 3. 把這個物件執向這個空間
*
* 正常順序 123
* 真實順序可能是 132 執行緒A沒問題
* 執行緒B可能有問題
*/
}
}
}
return lazyMan;//此時LazyMan還沒有完成構造
}
//反射!
public static void main(String[] args) throws Exception{
// LazyMan instance = LazyMan.getInstance();
Field swae_qj = LazyMan.class.getDeclaredField("swae_qj");
swae_qj.setAccessible(true);//把它也破壞
Constructor<LazyMan> declaredConstructors = LazyMan.class.getDeclaredConstructor(null);
declaredConstructors.setAccessible(true);//無視私有構造器
LazyMan instance = declaredConstructors.newInstance();//通過反射創建物件
swae_qj.set(instance,false);
LazyMan instance2 = declaredConstructors.newInstance();//通過反射創建物件
System.out.println(instance);
System.out.println(instance2);//反射可以破壞單例
}
}
/*
//單執行緒下OK
//多執行緒并發
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
*/
靜態內部類
//靜態內部類,只要是靜態內部類就 構造器私有
public class Holder {
private Holder(){
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER = new Holder();
}
}
單例不安全,反射
列舉
//enum 是什么? 本身也是一個Class 類
public enum EnumSingle {
INSTANCE;//本身就是單例
public EnumSingle getInstance(){
return INSTANCE;//能保證我這個物件一定是唯一的嗎?
}
}
class Test{
public static void main(String[] args) throws Exception{
EnumSingle instance1 = EnumSingle.INSTANCE;
//Cannot reflectively create enum objects
//反射不能破壞Enum的單例
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
//NoSuchMethodException: com.swae.single.EnumSingle.<init>()
//它說這個類 沒有空參的構造器
System.out.println(instance1);
System.out.println(instance2);
}
}
有參構造

列舉型別的最終反編譯原始碼:

結論:反射不能破壞Enum的單例
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/249425.html
標籤:其他
