單例模式-Singleton
阿新 • • 發佈:2021-10-14
1、餓漢式:
/** * 單例:餓漢式 * 缺點:可能會浪費空間 */ public class Singleton_Hurry { private static final Singleton_Hurry HURRY = new Singleton_Hurry(); //構造器私有化 private Singleton_Hurry() { System.out.println("成功建立物件!"+System.currentTimeMillis()); } /** * 提供公有方法來獲取例項 * @return */ public static Singleton_Hurry getInstance() { return HURRY; } public static void main(String[] args) { Singleton_Hurry h1 = Singleton_Hurry.getInstance(); Singleton_Hurry h2 = Singleton_Hurry.getInstance(); System.out.println(h1.hashCode()); //1265094477 System.out.println(h2.hashCode()); //1265094477 } }
2、懶漢式:
/** * 單例:懶漢 * 這種寫法在單執行緒上是可以,但在多執行緒下會出現併發問題 */ public class Singleton_Lazy { //構造器私有化 private Singleton_Lazy() { System.out.println(Thread.currentThread().getName()+"ok!"); } private static Singleton_Lazy LAZY; public static Singleton_Lazy getInstance() { if (LAZY == null) { LAZY = new Singleton_Lazy(); } return LAZY; } public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(() -> { Singleton_Lazy.getInstance(); }).start(); } } }
支援多執行緒的懶漢式:
/** * 單例:懶漢 * 支援多執行緒(雙重檢測鎖) * 問題:不加 volatile會造成指令成排(可能建立不了例項) */ public class Singleton_Lazy { // 構造器私有化 private Singleton_Lazy() { System.out.println(Thread.currentThread().getName() + "ok!"); } // 避免指令重排 private volatile static Singleton_Lazy lazy; public static Singleton_Lazy getInstance() { // 雙重檢測鎖模式的單例 (DCL) if (lazy == null) { synchronized (Singleton_Lazy.class) { if (lazy == null) { lazy = new Singleton_Lazy();//它不是原子性操作 //1.分配記憶體空間 2.執行構造方法,初始化物件 3.把這個物件指向這個空間 } } } return lazy; } public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(() -> { Singleton_Lazy.getInstance(); }).start(); } } }
3、靜態內部類
public class Holder {
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass {
private static final Holder HOLDER = new Holder();
}
}
前三種單例會被反射破解:
public class Singleton_Lazy {
// 構造器私有化
private Singleton_Lazy() {
System.out.println(Thread.currentThread().getName() + "ok!");
}
// 避免指令重排
private volatile static Singleton_Lazy lazy;
public static Singleton_Lazy getInstance() {
// 雙重檢測鎖模式的單例 (DCL)
if (lazy == null) {
synchronized (Singleton_Lazy.class) {
if (lazy == null) {
lazy = new Singleton_Lazy();//它不是原子性操作
//1.分配記憶體空間 2.執行構造方法,初始化物件 3.把這個物件指向這個空間
}
}
}
return lazy;
}
public static void main(String[] args) throws Exception {
Singleton_Lazy lazy1 = Singleton_Lazy.getInstance();
System.out.println(lazy1.hashCode());
// 使用反射來破壞單例
Constructor<Singleton_Lazy> constructor = Singleton_Lazy.class.getDeclaredConstructor(null);
constructor.setAccessible(true);//可以訪問私有的構造器
Singleton_Lazy lazy2 = constructor.newInstance();
System.out.println(lazy2.hashCode());
}
}
解決單例被破解:
/**
* 三重檢測鎖
*/
public class Singleton_Lazy {
// 構造器私有化
private Singleton_Lazy(){
synchronized (Singleton_Lazy.class) {
if (lazy != null) {
throw new RuntimeException("不要試圖使用反射破壞異常!");
}
}
}
// 避免指令重排
private volatile static Singleton_Lazy lazy;
public static Singleton_Lazy getInstance() {
// 雙重檢測鎖模式的單例 (DCL)
if (lazy == null) {
synchronized (Singleton_Lazy.class) {
if (lazy == null) {
lazy = new Singleton_Lazy();//它不是原子性操作
//1.分配記憶體空間 2.執行構造方法,初始化物件 3.把這個物件指向這個空間
}
}
}
return lazy;
}
public static void main(String[] args) throws Exception {
Singleton_Lazy lazy1 = Singleton_Lazy.getInstance();
System.out.println(lazy1.hashCode());
// 使用反射來破壞單例
Constructor<Singleton_Lazy> constructor = Singleton_Lazy.class.getDeclaredConstructor(null);
constructor.setAccessible(true);//可以訪問私有的構造器
Singleton_Lazy lazy2 = constructor.newInstance();
System.out.println(lazy2.hashCode());
}
}
如果正常建立物件也不是單例:
public class Singleton_Lazy {
// 構造器私有化
private Singleton_Lazy(){
synchronized (Singleton_Lazy.class) {
if (lazy != null) {
throw new RuntimeException("不要試圖使用反射破壞異常!");
}
}
}
// 避免指令重排
private volatile static Singleton_Lazy lazy;
public static Singleton_Lazy getInstance() {
// 雙重檢測鎖模式的單例 (DCL)
if (lazy == null) {
synchronized (Singleton_Lazy.class) {
if (lazy == null) {
lazy = new Singleton_Lazy();//它不是原子性操作
//1.分配記憶體空間 2.執行構造方法,初始化物件 3.把這個物件指向這個空間
}
}
}
return lazy;
}
public static void main(String[] args) throws Exception {
Singleton_Lazy lazy1 = Singleton_Lazy.getInstance();
System.out.println(lazy1.hashCode());
// 使用反射來破壞單例
/*Constructor<Singleton_Lazy> constructor = Singleton_Lazy.class.getDeclaredConstructor(null);
constructor.setAccessible(true);//可以訪問私有的構造器
Singleton_Lazy lazy2 = constructor.newInstance();
System.out.println(lazy2.hashCode());*/
Singleton_Lazy lazy3 = Singleton_Lazy.getInstance();
System.out.println(lazy3.hashCode());
}
}
解決方法: