天天看點

Java 單例模式-雙重判斷、内部類、枚舉

================================

©Copyright 蕃薯耀 2022-05-20

https://www.cnblogs.com/fanshuyao/

一、餓漢模式

public class Hunger {
 
    /**
     * 增加final關鍵字,避免被修改
     */
    private static final Hunger hunger = new Hunger();
    
    /**
     * 私有化,避免建立對象
     */
    private Hunger() {};
    
    /**
     * 提供擷取對象的方法
     * @return
     */
    public static Hunger get() {
        return hunger;
    }
    
    
}      

二、餓漢模式(靜态塊)

可以通過配置檔案對執行個體進行初始化

import lqy.utils.PropertiesUtils;
 
public class HungerStatic {
 
 
    private static final HungerStatic hungerStatic;
    
    private String name;
    
    /**
     * 私有化,避免建立對象
     */
    private HungerStatic(String name) {
        this.name = name;
    };
    
    
    static {
        String name = PropertiesUtils.readKeyValue("config.properties", "name");
        hungerStatic = new HungerStatic(name);
    }
    
    
    /**
     * 提供擷取對象的方法
     * @return
     */
    public static HungerStatic get() {
        //System.out.println(hungerStatic);
        return hungerStatic;
    }
 
 
    /*
    @Override
    public String toString() {
        return "HungerStatic [name=" + name + "]";
    }
    */
    
    
}      

三、懶漢模式 - 同步方法

public class LazySafe {
 
    private static LazySafe lazySafe;
    
    private LazySafe() {}
    
    public static synchronized LazySafe get() {
        if(lazySafe == null) {
            lazySafe = new LazySafe();
        }
        
        return lazySafe;
    }
    
}      

四、懶漢模式 - 同步塊

public class LazySync {
 
    /**
     * 需要加volatile防止指令重排
     */
    private static volatile LazySync lazySync;
    
    private LazySync() {}
    
    public static LazySync get() {
        synchronized (LazySync.class) {
            if(lazySync == null) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                lazySync = new LazySync();
            }
        }
        return lazySync;
    }
}      

五、懶漢模式 - 雙重判斷

public class LazySyncDouble {
 
    /**
     * 需要加volatile防止指令重排
     */
    private static volatile LazySyncDouble lazySyncDouble;
    
    private LazySyncDouble() {}
    
    public static LazySyncDouble get() {
        if(lazySyncDouble == null) {
            synchronized (LazySyncDouble.class) {
                if(lazySyncDouble == null) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    lazySyncDouble = new LazySyncDouble();
                }
            }
        }
        return lazySyncDouble;
    }
}      

六、懶漢模式 - 内部類

/**
 * Inner是一個内部靜态類,當外部類 LazyInner 被加載的時候,并不會建立 Inner執行個體對象。
 * 隻有當調用 get() 方法時,Inner才會被加載,這個時候才會建立 instance。
 * instance 的唯一性、建立過程的線程安全性,都由 JVM 來保證。
 * 是以,這種實作方法既保證了線程安全,又能做到延遲加載。
 * @author islee
 *
 */
public class LazyInner {
 
    private LazyInner() {}
    
    /**
     * 靜态内部類
     *
     */
    private static class Inner{
        private static final LazyInner lazyInner = new LazyInner();
    }
    
    public static LazyInner get() {
        return Inner.lazyInner;
    }
}      

七、枚舉【最安全方式】

最安全,能預防反射和反序列化的安全問題

/**
 * Java虛拟機會保證枚舉類型不能被反射并且構造函數隻被執行一次。
 * [最安全],其他的會存在反射和反序列化的安全問題
 *
 */
public class SingletonEnum {
 
    private SingletonEnum() {}
    
    private enum SingletonHolder {
 
        INSTANCE;
        
        private final SingletonEnum singletonEnum;
        
        private SingletonHolder() {
            singletonEnum = new SingletonEnum();
        }
        
        private SingletonEnum get() {
            return singletonEnum;
        }
    }
    
    
    public static SingletonEnum get() {
        return SingletonHolder.INSTANCE.get();
    }
    
}      

測試:

import lqy.design.singleton.SingletonEnum;
 
public class SingletonEnumTest {
 
    public static void singletonEnum() {
        long startTime = System.currentTimeMillis();
        
        for(int i=0; i<15; i++){
            new Thread(()-> {
                System.out.println(SingletonEnum.get());
            }).start(); 
        }
        
        long endTime = System.currentTimeMillis();
        System.out.println("耗時:" + (endTime - startTime));
    }
    
    public static void main(String[] args) {
        singletonEnum();
        
    }
}      

(時間寶貴,分享不易,捐贈回饋,^_^)

================================

©Copyright 蕃薯耀 2022-05-20

https://www.cnblogs.com/fanshuyao/

今天越懶,明天要做的事越多。

繼續閱讀