软件设计模式之单例模式

设计模式之单例模式

定义

保证一个类仅有一个实例,并提供一个全局访问点

类型

创建型

使用场景

想确保任何情况下都绝对只有一个实例

优点

在内存里只有一个实例,减少了内存开销。
可以避免对资源的多重占用。
设置全局访问点,严格控制访问。

缺点

没有接口,扩展困难

重点

  • 私有构造器
  • 线程安全
  • 延迟加载,想使用的时候再创建
  • 序列化和反序列化安全
  • 反射:防止反射攻击

实用技能

  • 反编译
  • 内存原理
  • 多线程Debug

相关设计模式

  • 单例模式和工厂模式
  • 单例模式和享元模式

懒汉模式

在需要的时候才实例化对象。
但是这种模式会存在线程安全问题。

传统懒汉模式

代码如下:

public class LazySingleton {
    private static LazySingleton lazySingleton = null;

    /**
     * 私有构造器
     */
    private LazySingleton() {

    }

    public static LazySingleton getInstance() {
        if (lazySingleton == null) {
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

双重检查懒汉模式

public class LazyDoubleCheckSingleton {

    private static volatile LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;

    private LazyDoubleCheckSingleton() {

    }

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

JVM创建对象有以下几步:

1、给对象分配内存空间;
2、初始化对象;
3、设置实例指向刚分配的内存地址;
4、初次访问对象。

但是在实际的创建对象的过程中,2,3两步有可能出现指令重排,也就是先执行3,2的顺序,这种改变在单线程中是没有问题的,实际在多线程中也没太大的问题,只是出现极端情况下,会出现问题,如下图所示:

volatile有两个作用:内存可见性和禁止指令重排。在这段代码中保证了指令的顺序性,不会重排序。

案例

  • 线程池
  • 日志操作

猜你喜欢

转载自www.cnblogs.com/xiaotutu365/p/10367496.html
今日推荐