Java设计模式-单例模式(2)

Java设计模式-单例模式(2)_第1张图片

    大家好,我是馆长!从今天开始馆长开始对java设计模式的创建型模式中的单例、原型、工厂方法、抽象工厂、建造者单例模式进行讲解和说明。

单例模式(Singleton)

定义

    某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。

目的

    节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。

特点

1.单例类只有一个实例对象;

2.该单例对象必须由单例类自行创建

3.单例类对外提供一个访问该单例的全局访问点

优点:

  • 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。

  • 避免对资源的多重占用(比如写文件操作)。

缺点:

    没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

结构

单例模式的主要角色如下。

·单例类:包含一个实例且能自行创建这个实例的类。

·访问类:使用单例的类。

Java设计模式-单例模式(2)_第2张图片

注意点

1.单例模式是自关联关系设计。

2.字段 instance 为private,static, volatile修饰。

3.getInstance(全局访问点)为public ,static 修饰,其中涉及了 synchronized关键字的使用 。

4. 构造函数为private(私有的)。

volatile:

        volatile关键字是为了保证线程安全的,当某个线程对共享变量只是读操作而没有写操作时,使用volatile就可以保证线程安全。volatile的作用是保证可见性和有序性,因为读操作本来就具有原子性,因此仅使用volatile就可以保证线程安全。

synchronized:

        多个线程使用同一个对象进行加锁(基于对象头加锁),可以实现线程间的同步互斥。简单地说,它的原理就是基于对象头加锁,满足原子性、可见性、有序性。

懒汉式(线程安全)

是否 Lazy 初始化:

是否多线程安全:

实现难度:

描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。

public class LazySingleton {
    //保证 instance 在所有线程中同步
    private static volatile LazySingleton instance = null;
    private LazySingleton() {
    }    //private 避免类在外部被实例化

    //synchronized 修饰方法级别
    public static synchronized LazySingleton getInstance() {
        //getInstance 方法前加同步
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

懒汉式(线程不安全)

是否 Lazy 初始化:

是否多线程安全:

实现难度:

描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。

public class LazySingleton {
        private static LazySingleton instance;
        private LazySingleton (){}
        public static LazySingleton getInstance() {
            if (instance == null) {
                instance = new LazySingleton();
            }
            return instance;
        }
}
饿汉式(线程安全)

是否 Lazy 初始化:

是否多线程安全:

实现难度:

描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存

 
public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton (){}
    public static Singleton getInstance() {
        return instance;
    }
}
 

【推荐】双检锁/双重校验锁(DCL,即 double-checked locking)

JDK 版本:JDK1.5 起

是否 Lazy 初始化:

是否多线程安全:

实现难度:较复杂

描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。getInstance() 的性能对应用程序很关键。

public class Singleton {
    private volatile static Singleton singleton;
    private Singleton (){}
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

登记式/静态内部类

是否 Lazy 初始化:

是否多线程安全:

实现难度:一般

描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。调用getInstance()方法时才创建,达到了类似懒汉式的效果,同时又是线程安全的。

public class Singleton {
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton (){}
    public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

枚举

JDK 版本:JDK1.5 起

是否 Lazy 初始化:

是否多线程安全:

实现难度:

优点:线程安全,不用担心反射破坏单例模式,性能高,没有任何锁。

缺点:枚举类占用内存多。

描述:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。

public enum Singleton {
    INSTANCE;
    public void otherMethod() {
        //处理其他功能业务
    }
}

        23 种设计模式不是孤立存在的,很多模式之间存在一定的关联关系,在大的系统开发中常常同时使用多种设计模式,或者模式与模式之间的组合进行生成更加强大的程序功能。

    好了,关于单例模式的说明,馆长就先讲到这里,最近馆长了解到单例模式实现不仅仅是上述的几种,随着软件行业的发展,各种变种也开始流行。由于时间和精力问题,馆长就先整理这些。谢谢各位看官!!


馆长准备了很多学习资料,其中包含java方面,jvm调优,spring / spring boot /spring cloud ,微服务,分布式,前端,js书籍资料,视频资料,以及各类常用软件工具,破解工具 等资源。请关注“IT技术馆”公众号,进行关注,馆长会每天更新资源和更新技术文章等。请大家多多关注。

你可能感兴趣的:(JAVA软件设计模式(GOF),java,开发语言)