6

设计模式——单例模式_大鱼的技术博客_51CTO博客

 2 years ago
source link: https://blog.51cto.com/learningfish/5372049
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

单例设计模式介绍

  • 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对 象实例,并且该类只提供一个取得其对象实例的方法(静态方法)

单例设计模式八种方式

  • 饿汉式(静态常量)
  • 饿汉式(静态代码块)
  • 懒汉式(线程不安全)
  • 懒汉式(线程安全, 同步方法)
  • 懒汉式(线程安全,同步代码块)
  • 静态内部类

饿汉式(静态常量)

class Singleton {
    
    /**
     * 1、构造器私有化
     */
    private Singleton(){}

    /**
     * 2、内部创建对象实例
     */
    private final static Singleton instance = new Singleton();

    /**
     * 3、提供获取方法
     */
    public static Singleton getInstance() {
        return instance;
    }
}

饿汉式(静态代码块)

class Singleton {
    /**
     * 1、构造器私有化
     */
    private Singleton(){
    }

    /**
     * 2、创建对象实例(去掉final)
     */
    private static Singleton instance;

    /**
     * 3、静态代码块中创建单例对象
     */
    static {
        instance = new Singleton();
    }

    /**
     * 4、提供获取方法
     */
    public static Singleton getInstance() {
        return instance;
    }
}

饿汉式优缺点说明:

  • 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。
  • 缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费
  • 这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,在单例模式中大多数都是调用getInstance方法,但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance就没有达到lazy loading的效果。
  • 结论:这种单例模式可用,可能造成内存浪费

懒汉式(线程不安全)

class Singleton {
    private static Singleton instance;

    private Singleton(){}

    /**
     * 提供静态方法,当使用方法时,才去创建instance
     * @return
     */
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }

        return instance;
    }

}

懒汉式(线程不安全)优缺点说明:

  • 优点起到了 Lazy Loading的效果,但是只能在单线程下使用
  • 缺点:如果在多线程下, 一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。
  • 结论: 在实际开发中,不要使用这种方式

懒汉式(线程安全,同步方法)

class Singleton {
    private static Singleton instance;

    private Singleton() {

    }


    /**
     * 加入synchronized 实现线程安全
     * @return
     */
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }

        return instance;
    }
    
}

懒汉式(线程安全,同步代码块)

class Singleton {
    private static Singleton instance;

    private Singleton() {

    }
    
    /**
     * 加入synchronized 实现线程安全
     * @return
     */
    public static Singleton getInstance() {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
            }
        }

        return instance;
    }


}

懒汉式(线程安全)优缺点说明:

  • 优点解决了线程安全问题
  • 缺点:效率太低了,每个线程在想获得类的实例时候,执行getInstance(方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了,方法进行同步效率太低
  • 结论:在实际开发中,不推荐使用这种方式
class Singleton {
    // 对象的创建可能发生指令的重排序
    // 使用 volatile 可以禁止指令的重排序
    // 保证多线程环境内的系统安全。
    private static volatile Singleton instance;
    
    private Singleton() {}

    /**
     * 双重检查机制
     * @return
     */
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

双重检查优缺点说明:

  • Double-Check 概念是多线程开发中常使用到的,如代码中所示,我们进行了两次if (singleton == null)检查,这样就可以保证线程安全了
  • 这样, 实例化代码只用执行一次,后面再次访问时,判断if (singleton == nul),直接return实例化对象,也避免的反复进行方法同步
  • 线程安全; 延迟加载;效率较高
  • 结论:在实际开发中,推荐使用这种单例设计模式

静态内部类

class Singleton  {
    private Singleton(){}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }


    public static Singleton getInstance(){
        return SingletonInstance.INSTANCE;
    }

}

静态内部类优缺点说明:

  • 这种方式采用了类装载的机制来保证初始化实例时只有一 个线程
  • 静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。
  • 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的
  • 优点: 避免了线程不安全,利用静态内部类特点实现延迟加载,效率高
  • 结论:推荐使用
enum Singleton {
    TEST1(1,"test1"),
    TEST2(2,"test2");

    private final Integer code;
    private final String msg;

    Singleton(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

枚举优缺点说明:

  • 这借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
  • 这种方式是Effective Java作者Josh Bloch提倡的方式
  • 结论: 推荐使用

单例模式注意事项和细节说明

  • 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于- -些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
  • 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new。
  • 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK