开发者社区> miaoikxm> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

单例模式的理解

简介: 谈谈你对单例模式的理解。也算是老生常谈的问题了~~~
+关注继续查看

2000元阿里云代金券免费领取,2核4G云服务器仅664元/3年,新老用户都有优惠,立即抢购>>>

一、作用

单个实例

保证我们的实例对象在整个应用程序中只有一个实例

二、创建方式

五种实现方式

2.1 饿汉式

在类加载的时候立即初始化,并且创建单例对象

它绝对线程安全,在线程出现以前就实例化了,不可能存在访问安全问题

优点:不加任何锁,执行效率比较高,用户体验比懒汉单例模式好

缺点:浪费内存,不管用不用都占着内存

public class HungrySingleton {

    // 直接实例化方式
//    private static final HungrySingleton hungrySingleton = new HungrySingleton();
    private static final HungrySingleton hungrySingleton;
    // 静态块单例模式
    static {
        hungrySingleton = new HungrySingleton();
    }
    private HungrySingleton(){}

    private static HungrySingleton getInstance(){
        return hungrySingleton;
    }
}

2.2 懒汉式

在外部调用的时候才进行实例化,相比较饿汉式避免了资源浪费

在单线程情况下,比较友好。

多线程情况下,会存在线程安全问题

public class LazySimpleSingleton {

    private LazySimpleSingleton() {
    }

    private static LazySimpleSingleton lazySimpleSingleton = null;

    public static LazySimpleSingleton getInstance() {
        if (null == lazySimpleSingleton) {
            lazySimpleSingleton = new LazySimpleSingleton();
        }
        return lazySimpleSingleton;
    }
}

2.3 双重检测锁(DCL)

基于懒汉式的线程安全问题,有了双重校验锁

public class LazyDoubleCheckSingleton {
    private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;

    /**
     * 私有化构造方法,防止直接通过new实例化
     */
    private LazyDoubleCheckSingleton() {
    }

    public static LazyDoubleCheckSingleton getInstance() {
        if (lazyDoubleCheckSingleton == null) {
            synchronized (LazyDoubleCheckSingleton.class) {
                if (lazyDoubleCheckSingleton == null) {
                    // 1.分配内存空间 2.执行构造方法,实例化对象 3.把这个对象赋给这个空间
                    // 不加volatile关键字,会造成指令重排,1,3,2
                    lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
                }
            }
        }
        return lazyDoubleCheckSingleton;
    }
}

2.4 静态内部类

public class StaticSingleton {

    public static class InnerStaticSingleton {
        /**
         * 声明外部类型的静态常量
         */
        public static final StaticSingleton instance = new StaticSingleton();
    }
    
    private StaticSingleton() {
    }

    public StaticSingleton getInstance() {
        return InnerStaticSingleton.instance;
    }
}

2.5 枚举类型

public enum  EnumSingleton {
    INSTANCE;

    public void handleMethod(){
        // 业务处理
    }
}

综上的五种写法,大多都是在考虑着线程安全问题

2.6 反射爆破问题

私有的构造器,可以通过反射去破坏。

在私有构造器中进行判断,进而抛出异常。

public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    LazySimpleSingleton instance = LazySimpleSingleton.getInstance();

    Class<LazySimpleSingleton> clazz = LazySimpleSingleton.class;
    Constructor<LazySimpleSingleton> constructor = clazz.getDeclaredConstructor();
    constructor.setAccessible(true);
    LazySimpleSingleton instance1 = constructor.newInstance();

    System.out.println(instance);
    System.out.println(instance1);
}

// 结果
com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2
com.example.validated.design.singleton.LazySimpleSingleton@45ff54e6

2.7 序列化与反序列化破坏单例

LazySimpleSingleton要实现Serializable序列化接口

public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException, ClassNotFoundException {
    LazySimpleSingleton instance = LazySimpleSingleton.getInstance();

    Class<LazySimpleSingleton> clazz = LazySimpleSingleton.class;
    Constructor<LazySimpleSingleton> constructor = clazz.getDeclaredConstructor();
    constructor.setAccessible(true);
    LazySimpleSingleton instance1 = constructor.newInstance();

    System.out.println(instance);
    System.out.println(instance1);

    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("d:/tools/a.txt"));
    outputStream.writeObject(instance);
    outputStream.flush();
    outputStream.close();

    ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("d:/tools/a.txt"));
    LazySimpleSingleton instance2 = (LazySimpleSingleton) inputStream.readObject();
    inputStream.close();
    System.out.println(instance);
    System.out.println(instance2);
}

// 结果
com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2
com.example.validated.design.singleton.LazySimpleSingleton@45ff54e6
com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2
com.example.validated.design.singleton.LazySimpleSingleton@5e265ba4

我们需要重写readResolve()方法

private Object readResolve() {
    return lazySimpleSingleton;
}

结果:

com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2
com.example.validated.design.singleton.LazySimpleSingleton@45ff54e6
com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2
com.example.validated.design.singleton.LazySimpleSingleton@6d5380c2

说明:readResolve()方法是基于回调的,反序列化时,如果定义了readResolve()则直接返回此方法指定的对象,而不需要再创建新的对象。

三、应用

在框架中看到的单例模式

  1. Spring中的Bean对象,默认是单例模式
  2. 相关的工厂对象都是单例,如:Mybatis中的SqlSessionFactory,Spring中BeanFactory
  3. 保存相关配置信息的都是单例,如:Mybatis中的Configuration对象,SpringBoot中的各个xxxAutoConfiguration对象
  4. 应用程序的日志应用,一般都会通过单例来实现
  5. 数据库的连接池的设计也是单例模式

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
单例模式
单例模式
30 0
单例模式
单例模式(Singleton Pattern),确保一个类只有一个实例,并提供对它的全局访问点。
315 0
单例模式
什么是单例模式?在一个项目中,单例模式确保某一个类只能有一个实例,这个类称为单例类。怎样确保某个类只能有一个实例,通常调用方法有两种方式: 创建类的一个对象,即new出一个对象,用该对象去调用类中方法; 使用类名直接调用类中方法,格式“类名.方法名()”想要类只有一个实例,必不能随意通过new出对象,禁止new对象就只能私有化构造方法,采用“类名.方法名()”这种方式获取方法。
1261 0
单例模式
《大话设计模式》阅读笔记和总结。原书是C#编写的,本人用Java实现了一遍,包括每种设计模式的UML图实现和示例代码实现。 目录:设计模式 Github地址:DesignPattern 定义:单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。
796 0
单例模式
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_40254498/article/details/79133275 懒...
531 0
单例模式
单例模式 标签 : Java与设计模式 经典的《设计模式:可复用面向对象软件的基础》一书归纳出23种设计模式, 23种设计模式又可划分为3类: 创建型模式, 结构型模式, 行为型模式.
930 0
单例模式
引用:http://zhidao.baidu.com/question/135442203.html&__bd_tkn__=2ab95b3a06619a2e4d5cec6fbdfe20ad9242d5f68078338d51fed8133ea5c69d362ad36bb4bcda3b39bb3949...
464 0
+关注
34
文章
2
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载
http://www.vxiaotou.com