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/

 
posted @ 2022-05-20 16:47  蕃薯耀  阅读(65)  评论(1编辑  收藏  举报