关于单例模式

目录

单例模式实现的步骤

单例模式实现的几个方式

饿汉式

饿汉式(静态常量初始化方式)

饿汉式(静态代码块初始化方式)

懒汉式

懒汉式(普通实现方式)

懒汉式(同步方法实现)

双重检查锁(推荐)

静态内部类实现(推荐)

枚举

避免反射对单例模式的破坏


单例模式可以防止重量型对象的反复创建消耗大量资源。

单例模式实现的步骤

1.构造器私有化

2.对外提供一个getInstance()方法来获取这个实例。

单例模式实现的几个方式

饿汉式

饿汉式(静态常量初始化方式)

public class Hunger {
    private final static Hunger INSTANCE = new Hunger();
    private Hunger(){}

    public static Hunger getInstance(){
        return INSTANCE;
    }
}

饿汉式(静态代码块初始化方式)

public class Hunger {
    private static final Hunger instance;
    static {
        instance = new Hunger();
    }
    private Hunger(){}

    public static Hunger getInstance(){
        return instance;
    }
}

饿汉式单例模式的优点:简单,避免了线程同步问题。

饿汉式单例模式的缺点:可能造成内存浪费。

懒汉式

懒汉式(普通实现方式)

public class Lazy {
    private static Lazy instance;
    public static Lazy getInstance(){
        if (instance == null){
            instance = new Lazy();
        }
        return instance;
    }
}

这种方式实现了懒加载,避免了内存浪费,但是存在线程同步问题

懒汉式(同步方法实现)

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

这种方式实现了懒加载,避免了线程同步问题,但是由于使用了同步方法,每次执行该方法都需要执行加锁和解锁操作,效率较低。

双重检查锁(推荐)

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

在加锁操作前判空,如果instance属性已经被new出来了就不需要进入加锁判断,直接返回对象,提高了执行效率。

在加锁操作后判空,避免有多个线程在第一个判空为true后修改instance变量。

对instance变量添加volatile关键字,避免指令重排:new一个对象包括:1.在堆内存开辟空间;2.对对象初始化;3.使变量指向这片空间。2和3两步可能发生指令重排,以132的方式执行,当完成13而2没有完成,就有一个其它线程拿到这个对象并执行操作就有可能发生错误。

静态内部类实现(推荐)

public class StaticInnerClass {

    private StaticInnerClass(){}

    public static StaticInnerClass getInstance(){
        return Inner.instance;
    }

    public static class Inner{
        public static StaticInnerClass instance;
        static {
            instance = new StaticInnerClass();
        }
    }
}

添加一个静态内部类,在静态内部类中实例化对象。

当外部类被加载时内部类不会被加载,只有调用getInstance()方法时才会加载内部类,并通过内部类的静态代码块对实例化一个对象,实现了懒加载。

类加载是只执行一次的,避免了线程同步问题。

枚举

枚举的实现是单例的

public enum EnumSingle {
    INSTANCE;
    public static EnumSingle getInstance(){
        return INSTANCE;
    }
}

获取到的EnumSingle.INSTANCE都是同一个对象。

当使用反射实例化有枚举类的时候会报错,可以避免反射对单例模式的破坏。

避免反射对单例模式的破坏

1.添加一个标志位,如果标志位出错则抛出异常

2.在构造器中判断instance是否为空,不为空则抛异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值