单例模式的实现(饿汉,双重校验锁,嵌套类,枚举)

学习链接:想真正了解JAVA设计模式看着一篇就够了。 详解+代码实例
设计模式涉及创建型模式、结构型模式和行为型模式。面试之中最常考创建型模式中的单例模式和工厂模式(因为这两个最简单。。。)。总结一下单例模式,之后总结工厂模式。

饿汉模式(不推荐)

public class Singleton {
    // 首先,将 new Singleton() 堵死
    private Singleton() {};
    // 创建私有静态实例,意味着这个类第一次使用的时候就会进行创建
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
    // 瞎写一个静态方法。这里想说的是,如果我们只是要调用 Singleton.getDate(...),
    // 本来是不想要生成 Singleton 实例的,不过没办法,已经生成了
    public static Date getDate(String mode) {return new Date();}
}

饿汉模式的缺点是当有多个静态方法时候,如果使用了非创建实例的静态方法,此时是不希望生成实例的,但是静态方法属于类,统一执行的,已经生成实例了。所以一般不使用这个。

饱汉模式(线程不安全)

public class Singleton {
    // 首先,将 new Singleton() 堵死
    private Singleton() {};
    // 创建私有静态实例,意味着这个类第一次使用的时候就会进行创建
    private static Singleton instance;

    public static Singleton getInstance() {
        instance = new Singleton();
        return instance;
    }
    // 延迟创建实例,当调用方法的时候才会创建实例
    public static Date getDate(String mode) {return new Date();}
}

双重校验锁(使用synchronized和volatile)

public class Singleton {
    // 首先,也是先堵死 new Singleton() 这条路
    private Singleton() {}
    // 和饿汉模式相比,这边不需要先实例化出来,注意这里的 volatile,它是必须的
    private static volatile Singleton instance = null;

    public static Singleton getInstance() {
        if (instance == null) {
            // 加锁
            synchronized (Singleton.class) {
                // 这一次判断也是必须的,不然会有并发问题
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

第一次校验:由于单例模式只需要创建一次实例,如果后面再次调用getInstance方法时,则直接返回之前创建的实例,因此大部分时间不需要执行同步方法里面的代码,大大提高了性能。如果不加第一次校验的话,那跟上面的懒汉模式没什么区别,每次都要去竞争锁。

第二次校验:如果没有第二次校验,假设线程t1执行了第一次校验后,判断为null,这时t2也获取了CPU执行权,也执行了第一次校验,判断也为null。接下来t2获得锁,创建实例。这时t1又获得CPU执行权,由于之前已经进行了第一次校验,结果为null(不会再次判断),获得锁后,直接创建实例。结果就会导致创建多个实例。所以需要在同步代码里面进行第二次校验,如果实例为空,则进行创建。

需要注意的是,private static volatile SingleTon3 singleTon=null;需要加volatile关键字,否则会出现错误。问题的原因在于JVM指令重排优化的存在。在某个线程创建单例对象时,在构造方法被调用之前,就为该对象分配了内存空间并将对象的字段设置为默认值。此时就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化。若紧接着另外一个线程来调用getInstance,取到的就是状态不正确的对象,程序就会出错。

嵌套类

public class Singleton3 {

    private Singleton3() {}
    // 主要是使用了 嵌套类可以访问外部类的静态属性和静态方法 的特性
    private static class Holder {
        private static Singleton3 instance = new Singleton3();
    }
    public static Singleton3 getInstance() {
        return Holder.instance;
    }
}

枚举

枚举类实现单例模式相当硬核,因为枚举类型是线程安全的,且只会装载一次。使用枚举类来实现单例模式,是所有的单例实现中唯一一种不会被破坏的单例模式实现。

public class SingletonObject {

    private SingletonObject() {
    }

    private enum Singleton {
        INSTANCE;

        private final SingletonObject instance;

        Singleton() {
            instance = new SingletonObject();
        }

        private SingletonObject getInstance() {
            return instance;
        }
    }

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单例模式主要是为了确保一个只有一个实例,其实现方式一般有饿汉式和懒汉式两种。 饿汉单例模式是在加载时就创建单例对象,无需任何判断或定操作,因此具有线程安全性。实现方式是将单例对象作为静态成员变量直接进行初始化,代码如下: ``` public class Singleton { private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } } ``` 懒汉式单例模式则是在需要使用时才创建单例对象,相比饿汉式更加节约资源。但是需要考虑线程安全问题。常见的实现方式有双重校验和静态内部双重校验利用同步保证对象只被创建一次,通过双重判断,减少了的开销。代码实现如下: ``` public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } ``` 静态内部实现方式则是将单例对象作为静态成员内部,并在外部中提供静态方法获取内部对象,在需要使用时才进行加载。由于加载的线程安全性,所以这种方式可以保证对象的线程安全性。代码实现如下: ``` public class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值