专栏首页栗霖积跬步之旅一天一个设计模式:单例模式

一天一个设计模式:单例模式

概念:

作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化,并向整个系统提供这个实例。

特点:

  1.单例类只能有一个实例

  2.单例类必须创建自己的唯一实例

  3.单例类必须给其他所有对象提供这一实例。

饿汉式单例类

public class EagerSingleton {
    private static EagerSingleton instance = new EagerSingleton();
    /**
     * 私有默认构造子
     */
    private EagerSingleton(){}
    /**
     * 静态工厂方法
     */
    public static EagerSingleton getInstance(){
        return instance;
    }
}

由于选用的是静态资源,在类加载的时候,静态变量instance就会被初始化,类的唯一变量也在这时候创建了出来。

饿汉式,顾名思义,急于创建对象,在类加载的时候就完成了对象的创建。

饿汉式是一种采用“空间换取时间”,当类装载的时候就会创建类的实例,不管你用不用,先创建,调用的时候,无需判断直接使用,节约了时间。

懒汉式单例

public class LazySingleton {
    private static LazySingleton instance = null;
    /**
     * 私有默认构造子
     */
    private LazySingleton(){}
    /**
     * 静态工厂方法
     */
    public static synchronized LazySingleton getInstance(){
        if(instance == null){
            instance = new LazySingleton();
        }
        return instance;
    }
}

只有在真正需要的时候才会去创建,采用的是时间换空间,由于是线程安全的,会降低访问速度。固可使用双检锁的方式进行优化。

双重检查加锁

机制:并不是每次进入getInstance方法都需要同步,而不是先同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一检查,进入同步块后,在检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查,这样一来就只需要同步一次,减少了多次在同步情况下进行判断所浪费的时间。

双检锁的关键是,使用volatile,它在此处的作用是,该变量将不会被某一个线程缓存,而是在共享内存中,被所有进行读写的内存共享到,从而保证多个线程能够正确处理该变量。

public class Singleton {
    private volatile static Singleton instance = null;
    private Singleton(){}
    public static Singleton getInstance(){
        //先检查实例是否存在,如果不存在才进入下面的同步块
        if(instance == null){
            //同步块,线程安全的创建实例
            synchronized (Singleton.class) {
                //再次检查实例是否存在,如果不存在才真正的创建实例
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

注:由于volatile关键字会屏蔽虚拟机的一些代码优化,所以运行效率并不高,所有其实应该尽量避免使用双检锁的方式来实现单例。

懒加载模式(内部类形式)

什么是内部类:

  内部类就是指在类里面的类,被static修饰的内部类,称为类级内部类,无static修饰的内部类称为对象级内部类。

  类级内部类是外部类的static部分,它的对象与外部类对象间并没有依赖关系,因此可以直接创建。而对象级内部类的实例,是绑定在外部对象的实例中的。

  类级内部类中,可以定义静态方法,在静态方法中只能够引用外部类中的静态成员或者成员变量。

  类级内部类相当于外部类的成员,只有在第一次被使用的时候才会加载。

多线程缺省同步锁的相关知识:

  在下面操作下,jvm会自动为该操作进行同步,以避免出现并发安全问题。

  1.由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据。

  2.访问final字段时,

  3.在创建线程前创建对象时,

  4.线程可以看见它将要处理的对象时。

综上的解决思路:

  采用静态初始化器的方式通过jvm来保证线程的安全性,采用类级内部类的方式实现延迟加载。

public class Singleton {
    
    private Singleton(){}
    /**
     *    类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
     *    没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
     */
    private static class SingletonHolder{
        /**
         * 静态初始化器,由JVM来保证线程安全
         */
        private static Singleton instance = new Singleton();
    }
    
    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
}

  在getInstance第一次被调用时,会读取内部类的instance,这时,类级内部类完成初始化,从而创建单例,实现了延时加载,由于是静态成员,只有在类加载的时候才加载一次,且通过jvm的缺省方式实现了线程安全问题。

单例类枚举:

  单元素的枚举类型已经成为实现Singleton的最佳方法。用枚举来实现单例非常简单,只需要编写一个包含单个元素的枚举类型即可。

public enum Singleton {
    /**
     * 定义一个枚举的元素,它就代表了Singleton的一个实例。
     */
    
    uniqueInstance;
    
    /**
     * 单例可以有自己的操作
     */
    public void singletonOperation(){
        //功能处理
    }
}

  使用枚举来实现单实例控制会更加简洁,而且无偿地提供了序列化机制,并由JVM从根本上提供保障,绝对防止多次实例化,是更简洁、高效、安全的实现单例的方式。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 第12章:汇总数据

    表名:products  字段:product_id、product_name、product_price、vend_id(供应商) 12.1聚集函数: 我们常...

    用户1134788
  • java多线程编程核心技术——第六章总结

    1.0立即加载/“饿汉式”   立即加载:实用类的时候已经将对象创建完毕,常见的实现方法就是直接new实例化。   注:是在调用方法前,就已经实例化了(通常是...

    用户1134788
  • 异常:This application has no explicit mapping for /error, so you are seeing this as a fallback.

    出现这个异常说明了跳转页面的url无对应的值. 原因1: Application启动类的位置不对.要将Application类放在最外侧,即包含所有子包  原因...

    用户1134788
  • 设计模式 - 单例模式 - JavaScript

    如果一个类负责连接数据库的线程池、日志记录逻辑等等,此时需要单例模式来保证对象不被重复创建,以达到降低开销的目的。

    心谭博客
  • Android编程设计模式之单例模式实例详解

    本文实例讲述了Android编程设计模式之单例模式。分享给大家供大家参考,具体如下:

    砸漏
  • java实现单例模式

    public class Singleton{ private static Singleton instance = new Singleton(); p...

    实时计算
  • 单例模式

    单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,属于创建型模式。 单例模式定义:保证一个类仅有一个实例,并提供一个访问它...

    卡尔曼和玻尔兹曼谁曼
  • 单例模式简单复杂,线程不安全到安全

    说到单例模式,可以说单例模式是最常见,也是最常用的设计模式了。Spring的bean默认就是单例的。虽然单例模式是最简单的设计模式,但是在实现上有多种方式,分别...

    java乐园
  • Windows下PHP环境搭建——WAMP分享

    01 导语 学习一门语言,就得从搭建开发环境开始。PHP学习者时常会接触到一个词WAMP,那么WAMP是什么意思呢?Windows系统下的Apache+Mysq...

    企鹅号小编
  • 漫画:什么是单例模式?(整合版)

    ————— 第二天 ————— 单例模式第一版: public class Singleton { private Singleton() {} ...

    程序猿DD

扫码关注云+社区

领取腾讯云代金券