1. 程式人生 > 其它 >設計模式(一)單例模式

設計模式(一)單例模式

餓漢式,DCL懶漢式

1、餓漢式單例

/**
 * 餓漢式單例
 * @author it-小林
 * @date 2021年07月05日 9:05
 */
public class HungryPattern {

    //可能會浪費空間,開闢了空間,卻沒有使用
    private HungryPattern(){

    }

    private final static HungryPattern hungryPattern = new HungryPattern();

    public final HungryPattern getInstance(){
        return
hungryPattern; } }

2、餓漢式單例

(1)存在多執行緒併發模式,也就是說多執行緒模式下,會有問題。

 1 /**
 2  * @author it-小林
 3  * @date 2021年07月05日 9:11
 4  */
 5 public class LazyPattern {
 6 
 7     private LazyPattern() {
 8 
 9     }
10 
11     private static LazyPattern lazyPattern;
12 
13     private static LazyPattern getInstance(){
14 if(lazyPattern == null){ 15 lazyPattern = new LazyPattern(); 16 } 17 return lazyPattern; 18 } 19 20 //多執行緒開發 21 public static void main(String[] args) { 22 Thread thread1 = new Thread(){ 23 @Override 24 public void run() {
25 System.out.println(LazyPattern.getInstance()); 26 } 27 }; 28 thread1.start(); 29 Thread thread2 = new Thread(){ 30 @Override 31 public void run() { 32 System.out.println(LazyPattern.getInstance()); 33 } 34 }; 35 thread2.start(); 36 } 37 }

(2)雙重檢測鎖模式的 懶漢式單例 DCL懶漢式

注意:synchronized解決併發問題,但是因為lazyMan = new LazyMan();不是原子性操作(可以分割,見程式碼註釋),可能發生指令重排序的問題,通過volatil來解決。

  • Java 語言提供了 volatile和 synchronized 兩個關鍵字來保證執行緒之間操作的有序性,volatile 是因為其本身包含“禁止指令重排序”的語義,synchronized 是由“一個變數在同一個時刻只允許一條執行緒對其進行 lock 操作”這條規則獲得的,此規則決定了持有同一個物件鎖的兩個同步塊只能序列執行;

  • 原子性就是指該操作是不可再分的。不論是多核還是單核,具有原子性的量,同一時刻只能有一個執行緒來對它進行操作。簡而言之,在整個操作過程中不會被執行緒排程器中斷的操作,都可認為是原子性。比如 a = 1。
/**
 * @author it-小林
 * @date 2021年07月05日 9:11
 */
public class LazyPattern {

    private LazyPattern() {

    }

    private static LazyPattern lazyPattern;

    //雙重檢測模式的  懶漢式單例   DCL懶漢式
    private static LazyPattern getInstance(){
        if(lazyPattern == null){
            synchronized (LazyPattern.class){
                if(lazyPattern == null){
                    //不是一個原子性操作
                    lazyPattern = new LazyPattern();
                    /**
                     * 1.分配記憶體空間
                     * 2、執行構造方法,初始化物件
                     * 3、把這個物件指向這個空間
                     */
                }
            }
        }

        return lazyPattern;
    }

    //多執行緒開發
    public static void main(String[] args) {
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                System.out.println(LazyPattern.getInstance());
            }
        };
        thread1.start();
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                System.out.println(LazyPattern.getInstance());
            }
        };
        thread2.start();
    }
}

3、靜態內部類

 1 /**
 2  * 靜態內部類
 3  * @author it-小林
 4  * @date 2021年07月05日 19:29
 5  */
 6 public class Holder {
 7 
 8     //構造器私有
 9     public Holder() {
10 
11     }
12 
13     public static Holder getInstance(){
14         return InnerClass.HOLDER;
15     }
16 
17     public static class InnerClass{
18         private static final Holder HOLDER = new Holder();
19     }
20 
21 }

4、單例不安全,反射破壞(見註釋及main方法中反射破解步驟)

 1 /**
 2  * @author 林瑞濤
 3  * @date 2021年07月05日 9:11
 4  */
 5 public class LazyPattern {
 6 
 7     //紅綠等解決通過反射建立物件(反編譯可以破解該方法)
 8     private static boolean bolNew = false;
 9     private LazyPattern() {
10         synchronized (LazyPattern.class){
11             if(bolNew == false){
12                 bolNew = true;
13             }else{
14                 throw new RuntimeException("不要試圖使用反射破壞單例");
15             }
16         }
17     }
18 
19     //volatile避免指令重排
20     private volatile static LazyPattern lazyPattern;
21 
22 
23     //雙重檢測模式的  懶漢式單例   DCL懶漢式
24     private static LazyPattern getInstance(){
25 
26         if(lazyPattern == null){
27             //不是一個原子性操作
28             lazyPattern = new LazyPattern();
29         }
30         return lazyPattern;
31     }
32 
33     //反射
34     public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
35         Field bolNew = LazyPattern.class.getDeclaredField("bolNew");
36         bolNew.setAccessible(true);
37 
38         Constructor<LazyPattern> declaredConstructor = LazyPattern.class.getDeclaredConstructor(null);
39         declaredConstructor.setAccessible(true);//無視私有的構造器
40         LazyPattern instance1 = declaredConstructor.newInstance();
41         bolNew.set(instance1,false);
42         System.out.println(instance1);
43         LazyPattern instance2 = declaredConstructor.newInstance();
44 
45         System.out.println(instance2);
46     }
47 }

列舉:通過反射破解枚舉發現不成功:
1、普通的反編譯會欺騙開發者,說enum列舉是無參構造
2、實際enum為有參構造(見後面);
3、通過反射破解列舉會發現丟擲異常
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at com.ph.single.Test.main(EnumSingle.java:19)

 1 //enmu是什麼?本身也是一個class類
 2 public enum EnumSingle {
 3     INSTANCE;
 4     public EnumSingle getInstance(){
 5         return INSTANCE;
 6     }
 7 }
 8 
 9 class Test{
10     public static void main(String[] args) throws Exception {
11         EnumSingle instance = EnumSingle.INSTANCE;
12         Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
13         declaredConstructor.setAccessible(true);
14         EnumSingle instance2 = declaredConstructor.newInstance();
15 
16         //java.lang.NoSuchMethodException: com.ph.single.EnumSingle.<init>()
17         System.out.println(instance);
18         System.out.println(instance2);
19 
20     }
21 }

通過idea和jdk自帶的反編譯列舉如下:

通過JDK反編譯列舉的程式碼如下,發現列舉其實是有參構造

初出茅廬,多多指教