浅谈设计模式

存在目的

节约资源确保系统中某个类只有一个实例。(确保对象的唯一性,避免不必要的系统开销)

单例模式的三个要点

由三个要点可知单例模式的结构特点

  • 内部实现只生成一个实例
  • 提供静态的 getInstance() 工厂方法,让客户可以访问它的唯一实例
  • 构造函数设为私有,在单例类内部定义一个静态 Singleton 类型对象,作为外界使用的唯一实例

基本 UML 图

单例模式实现方式

饿汉式
public class EagerSingleton {
    
    private final 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 LazySingleton getInstance() {
        if (instance == null)
            instance = new LazySingleton();
        return instance;
    }
}

这是最简单的懒汉式,只有用到的时候才去判断有没有实例,但是这样 getInstance() 并不能在多线程时保证只创建出一个实例,可以修改为:

public static LazySingleton getInstance() {
        if (instance == null)
            synchronized (LazySingleton.class) {
                instance = new LazySingleton();
            }
        return instance;
}

因为 判空和 new 对象的操作并不是原子操作,所以依然不能保证原自性,也就也可能,A、B 线程先后访问 instance 为 null,A 在 new 对象,而 B 在等锁,然后 B 又去 new 了一个实例。同样不能保证原子性。

把整个 getInstance() 方法加锁来保证原子性的话,作为一个单例被各种其他类访问的第一步都是在 getInstance(),这样会在多线程的时候影响执行效率,所以又有了下面这种:

public class LazySingleton {

    private static volatile LazySingleton instance = null;

    private LazySingleton() {
    }

    public static LazySingleton getInstance() {
        if (instance == null)
            synchronized (LazySingleton.class) {
                if (instance == null)
                    instance = new LazySingleton();
            }
        return instance;
    }
}

这样貌似就完美的解决了执行效率和实例唯一性的问题。但是需要注意到的一点是:必须在 instance 前面加修饰符 volatile 来确保多线程正确处理。

volatile 只有在 JDK 1.5 以及以上的版本才能正确执行。volatile 会屏蔽一些 Java 虚拟机的优化,而影响执行效率。可见上面这种双重判断锁定也不是一种完美的单例解决方案。

静态内部类实现单例(完美方案)
public class Singleton {
    private Singleton() {
    }

    public static Singleton getInstance() {

        return HolderClass.instance;
    }

    private static class HolderClass{
        private final static Singleton instance = new Singleton();
    }
}

这种方式实现了延时加载,保证了线程的安全性,又不影响系统性能。

单例模式优缺点

优点
  • 单例模式提供了对唯一实例的受控访问,可以严格控制客户端怎样以及何时访问它
  • 由于系统内只存在一个对象,比较节约系统资源。对于创建开销比较大,或者频繁创建开销的使用单例可以明显的提升性能。
缺点
  • 单例模式没有抽象层,不利于拓展
  • 违反了单一职责的原则,单例类既充当工厂,又充当产品的角色。将产品的创建和产品本身的功能融合到了一起。
  • 长时间不被利用时,可能被当作垃圾回收掉。下次还要初始化实例。可能会引起必要的实例状态的丢失。

单例模式适用场景

  • 系统只需要一个实例,或者是创建的开销太大,只允许创建一个实例
  • 客户端使用实例只允许通过一个公共访问点,除了公共访问点以外不允许其他的途径来访问实例。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值