4

单例模式五种实现方式以及在JDK中的体现 - 编程小白Jxh

 6 months ago
source link: https://www.cnblogs.com/jiaxh/p/18024633
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

单例模式五种实现方式以及在JDK中的体现

一、五种实现方式

1、饿汉式

  • 提供一个静态私有的成员常量,类型就是单例类型,值是用私有构造创造出来的唯一实例
  • 提供公共的静态方法获取上述的静态成员常量
public class Singleton1 implements Serializable {
    //(1)构造私有
    private Singleton1(){
        //添加if判断防止单例模式被破坏
        if(INSTANCE != null) {
            throw new RuntimeException("单例构造器禁止反射调用");
        }
        System.out.println("private Singleton1()");
    }
    //(2)提供一个静态私有的成员常量,类型就是单例类型,值是用私有构造创造出来的唯一实例
    private static final Singleton1 INSTANCE = new Singleton1();
    //(3)提供公共的静态方法获取上述的静态成员常量
    public static Singleton1 getInstance() {
        return INSTANCE;
    }
}

注意:对应所有的单例模式实现方式,如果实现Serializable接口,可能会被反射,反序列化等操作破坏单例,

2、枚举饿汉式

  • 枚举类,只定义一个变量
  • 提供公共的静态方法获取枚举常量
public enum Singleton2 {
    //(1)枚举类,只定义一个变量
    INSTANCE;
    //(2)构造私有
    private Singleton2(){
        System.out.println("private Singleton3()");
    }
    //(3)获取枚举常量
    private static Singleton2 getInstance(){
        return INSTANCE;
    }

}

3、懒汉式

  • 提供一个静态私有的成员常量,类型就是单例类型,值为空
  • 当调用该方法时才new
  • 提供公共的静态方法获取上述的静态成员常量
public class Singleton3 {
    //(2)声明静态变量为空
    private static Singleton3 INSTANCE = null;
    //(1)构造私有
    private Singleton3(){
        System.out.println("private Singleton1()");
    }
    //(3)提供公共的静态方法获取上述的静态成员变量
    //添加synchronized保证在多线程情况下运行正常
    public static synchronized Singleton3 getInstance() {
        //(4)调用该方法时再new,通过判断是否为空可控制只创建一个实例
        if(INSTANCE == null) {
            INSTANCE=new Singleton3();
        }
        return INSTANCE;
    }
}

注意:如果在多线程下,要防止多次创建实例,则在静态方法上添加synchronized,但其实我们只要在第一次调用时保证线程安全就可以,因此此方式的效率比较低,如果要提高效率,可以参考下述两种实现方式。

4、DCL懒汉式-双检索懒汉式

DCL懒汉式是为了保证多线程下运行正常,同时提高效率,也就是在静态方法中加锁之前判断是否已经创建了实例。同时静态变量使用volatile修饰

public class Singleton4 {
    //(2)声明静态变量为空
    private static volatile Singleton4 INSTANCE = null;//可见性,有序性
    //(1)构造私有
    private Singleton4(){
        System.out.println("private Singleton1()");
    }
    //(3)提供公共的静态方法获取上述的静态成员变量,调用该方法时再new
    public static Singleton4 getInstance() {
        //在加锁之前进行判断
        if(INSTANCE == null) {//一次检索
            synchronized (Singleton4.class){
                if (INSTANCE == null){//二次检索
                    INSTANCE=new Singleton4();
                }
            }
        }
        return INSTANCE;
    }
}

5、懒汉式内部类单例模式

使用内部类的方式可以保证线程安全,建议使用

public class Singleton5 {
    //构造私有
    private Singleton5(){
        System.out.println("private Singleton5()");
    }
    //创建内部类,在内部类中新建实例
    private static class Holder{
        static Singleton5 INSTANCE=new Singleton5();
    }
    private static Singleton5 getInstance(){
        return Holder.INSTANCE;
    }
}

二、单例模式在jdk中的体现

  • Runtime类是单例模式,饿汉式单例实现
  • System类中的有一个Console类型的cons变量,采用DCL懒汉式方式实现
  • Collections类中有大量单例模式实现,采用内部类懒汉式实现

__EOF__

本文作者: 编程小白Jxh 本文链接: https://www.cnblogs.com/jiaxh/p/18024633 关于博主: 评论和私信会在第一时间回复。或者直接私信我。 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处! 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK