单例模式

单例模式(Singleton Pattern)

是指确保一个类在任何情况下都绝对只有一个实例
私有化构造方法,属于创建型模式(结构型模式/行为型模式)

1.饿汉式单例

不管使用使用到,在类加载是进行创建
缺点:浪费空间
public class HungrySingleton{
    //私有静态不可覆盖变量
    private static final HungrySingleton hungrySingleton; 
    
    //类加载时创建类实例
    static{
        hungrySingleton = new HungrySingleton();
    }
    
    //私有化构造方法
    private HungrySingleton(){}
    
    //静态获取实例方法
    public static HungrySingleton getInstace(){
        return hungrySingleton;
    }
}

2.懒汉式单例

类加载是并不初始化,第一次使用时进行初始化
public class LazySingleton{
    //私有静态变量,默认为空
    private static  LazySingleton lazySingleton=null; 
    
    //私有化构造方法
    private HungrySingleton(){}
    
    //静态获取实例方法,线程不安全实例可能会多次被创建
    public static LazySingleton getInstace(){
        if(lazySingleton == null){
            lazySingleton = new lazySingleton();
        }
        return lazySingleton;
    }
}

3.注册式单例

即:内部类模式单例(性能最优)
public class LazyInnerClassSingleton{

    //私有化构造方法
    private LazyInnerClassSingleton(){
        //防止反射破解
        if(LazyHolder.LAZY != null){
            throw new Exception("不允许构建多个实例");
        }
    }
    
    //静态获取实例方法,线程安全
    //①懒汉式加载
    //②LazyHoler中的逻辑,当getInstace被调用时候才知晓
    //③巧妙的运用了内部类的特性,JVM底层逻辑.完美的避免了线程安全问题
    public static fianl LazyInnerClassSingleton getInstace(){
       return LazyHolder.LAZY;
    }
    //防止序列化->反序列化对象破解单例
    private Object readResolve(){
        return LazyHolder.LAZY
    }
    
    //内部类
    private static  class LazyHolder{
        private static  final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
    }
}

//反射破解
public class Test{
    public static void main(String[] args0){
        try{
            Class<?> clazz = LazyInnerClassSingleton.class;
            java.lang.reflect.Conotructor c = clazz.getDeclaredConotructor(null);
            c.setAccessible(true);
            c.newInstance();
        }catch(Exception e){
            e.printStackTrace();
        }

    }   
}

3.1枚举式(注册式的一种)

/**
 * Description:数据库连接(被单例对象)
 *
 * @date 2019-05-09 16:23
 */

public class DBConnection {
}

/**
 * Description:数据源枚举
 *
 * @date 2019-05-09 16:10
 */

public enum DataSourceEnum {

    DATASOURCE;

    private DBConnection dbConnection;

    public DBConnection getDbConnection() {
        return dbConnection;
    }

    public static DataSourceEnum getInstance(){
        return DATASOURCE;
    }

    DataSourceEnum() {
        this.dbConnection = new DBConnection();
    }
}

/**
 * Description:测试
 *
 * @date 2019-05-09 16:14
 */

public class Test {
    public static void main(String[] args) {
        DBConnection con1 = DataSourceEnum.DATASOURCE.getDbConnection();
        DBConnection con2 = DataSourceEnum.DATASOURCE.getDbConnection();
        System.out.println(con1 == con2);
    }
}

原理

3.2容器式单例

① 私有化构造方法

②定义线程安全的容器(ConcurrentMap)

③获取对象时,先从容器内取,存在容器内直接返回;不出存在通过反射获取对象放入容器后进    行返回,注意线程安全问题,需要解决

3.3.ThreadLocal单例

伪线程安全:全局线程不安全,线程内线程安全
public class Apple{

    private Apple(){}
    
    private static final ThreadLocal<Apple> threadLocalInstance = new ThreadLocal<Apple>(){
        @Override
        protected Apple initiaValue(){
            return new Apple();
        }
    }
    
    public static Apple getInstance(){
        threadLocalInstance.get();
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。