枚举实现单例模式

写在前面

单例模式定义: 一个类 只能创建一个实例。

使用一个对象来做就不用实例化多个对象!这就能减少我们空间和内存的开销~

我们使用静态类.doSomething()和使用单例对象调用方法的效果是一样的啊。

没错,效果就是一样的。使用静态类.doSomething()体现的是基于对象,而使用单例设计模式体现的是面向对象。

编写单例模式的代码其实很简单,就分了三步:

将构造函数私有化

在类的内部创建实例

提供获取唯一实例的方法

常用的单例模式

  1. 饿汉式
public class Liuge36 {
   
    // 1.构造函数私有化
    private Liuge36(){

    }
    // 2.在类的内部创建实例
    private static Liuge36 liuge36 = new Liuge36();

    // 3.提供获取实例的唯一方法
    public static Liuge36 getInstance(){
        return liuge36;
    }

}

一上来就创建对象了,如果该实例从始至终都没被使用过,则会造成内存浪费。

  1. 简单懒汉式 (在方法上加锁)
    既然说一上来就创建对象,如果没有用过会造成内存浪费:
    那么我们就设计用到的时候再创建对象!
public class Liuge36 {
    // 1.将构造函数私有化
    private Liuge36(){

    }
    // 2.先不创建对象,等用到的时候 ,再开始创建
    private static Liuge36 liuge36 = null;
    
    /**
     * 3.调用获取实例的方法,说明要用到实例对象了
     * synchronized 加锁之后才能保证在多线程下代码可用,不加锁仅仅适用于单线程的情况
     */
    public static synchronized Liuge36 getInstance(){

        // 先判断对象是否为空,如果为空,先创建再返回出去
        if (liuge36 == null) {
            liuge36 = new Liuge36();
        }
        return liuge36;

    }
}
  1. DCL双重检测加锁(进阶懒汉式)
    上面那种直接在方法上加锁的方式其实不够好,因为在方法上加了内置锁在多线程环境下性能会比较低下,所以我们可以将锁的范围缩小。
public class Liuge36 {
    // 1.将构造函数私有化
    private Liuge36(){

    }

    /**
     * 利用静态变量liuge36来记录Liuge36的唯一实例
     *
     * volatile 关键字确保:当变量liuge36 被初始化成 Liuge36实例时,
     * 多个线程正确地处理liuge36变量
     *
     * volatile有内存屏障的功能!
     */
    private static volatile Liuge36 liuge36 = null;

    // 提供获取唯一实例的方法
    public static Liuge36 getInstance(){
        if (liuge36 == null){

            // 同步代码块 ,将锁的范围缩小,提高性能
            synchronized (Liuge36.class){
                // 再次判断对象是否创建过
                if (liuge36 == null){
                    liuge36 = new Liuge36();
                }
            }

        }
        return liuge36;
    }
}

  1. 静态内部类实现懒汉式
public class Liuge36 {
    // 1.将构造函数私有化
    private Liuge36(){

    }

    /**
     * 使用静态内部类的方式实现懒加载
     * 初始化静态数据时,Java提供了的线程安全性保证。(所以不需要任何的同步)
     */
    private static class LazyHolder{
        // 创建单例对象
        private static final Liuge36 instance = new Liuge36();
    }
    // 提供获取实例的唯一方法
    public static Liuge36 getInstance(){
        return LazyHolder.instance;
    }

}
  1. 枚举方式
    Joshua Bloch说“单元素的枚举类型已经成为实现Singleton的最佳方法
public class Liuge36 {
    // 1.将构造函数私有化
    private Liuge36(){

    }
    // 2 定义一个静态枚举类
    static enum SingletonEnum{
        INSTANCE;
        private Liuge36 liuge36;
        // 私有化枚举的构造函数

        private SingletonEnum(){
            liuge36 = new Liuge36();
        }

        public Liuge36 getLiuge36(){
            return liuge36;
        }
    }

    // 3. 提供获取实例的唯一方法
    public static Liuge36 getInstance(){
        return SingletonEnum.INSTANCE.getLiuge36();
    }

    public static void main(String [] args){
        System.out.println(Liuge36.getInstance());
        System.out.println(Liuge36.getInstance());
        System.out.println(Liuge36.getInstance()==Liuge36.getInstance());
    }

}

总的来说单例模式写法有5种:

饿汉式

简单懒汉式(在方法加锁)

DCL双重检测加锁(进阶懒汉式)

静态内部类实现懒汉式(最推荐写法)

枚举方式(最安全、简洁写法)

参考:java3y & https://www.jianshu.com/p/d35f244f3770

posted @ 2019-12-11 11:20  liuge36  阅读(404)  评论(0编辑  收藏  举报