单例(Singleton)模式

介绍

单例模式是Java中最简单的设计模式之一,这种类型的设计模式属于创建型模式,涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一对象的方式,可以直接访问,不需要实例化该类的对象

几种实现方式

懒汉式,延迟加载,线程不安全

这种方式是最基本的实现方式,存在的问题是不支持多线程,所以严格意义上也不能算单例模式。延迟加载,不要求线程安全,在多线程不能正常工作

public class Singleton {  
    private static Singleton instance;  

    //让构造函数为 private,这样该类就不会被实例化
    private Singleton (){}  
  
    public static Singleton getInstance() {  
        //延迟加载
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
} 

接下来几种实现方式都支持多线程,但是性能上有所差异

懒汉式,延迟加载,线程安全

这种方式同样支持延迟加载,能在多线程中工作,但是相对效率低,因为每次获取实例时都需要进行同步

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

饿汉式,不延迟加载,线程安全

这种方式比较常用,但容易产生垃圾对象,因为它虽然基于classLoader(类加载)机制避免了多线程的同步问题,但instance在类装载时就实例化,也不能确定还会有其他的方式导致类装载,这时候初始化instance很明显没有实现延迟加载

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
        return instance;  
    }  
}  

双重校验锁(DCL),延迟加载,线程安全

这种方式采用双锁机制,安全且在多线程情况下能保持高性能,不过Java5及以上版本才支持。这种机制并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块之后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查,这样一来,就只需要同步一次了

public class Singleton {  
    private volatile static Singleton singleton;  

    private Singleton (){}  

    public static Singleton getSingleton() {  
        if (singleton == null) {  
            synchronized (Singleton.class) {  
                if (singleton == null) {  
                    singleton = new Singleton();  
                }  
            }  
        }  
        return singleton;  
    }  
}  

代码中的关键字volatile意思是,被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量

登记式(静态内部类),延迟加载,线程安全

这种方式同样利用了classLoader机制来保证初始化instance时只有一个线程,但与饿汉式方式不同的是,饿汉式只要Singleton类被装载了,那么instance就会被实例化,没有达到延迟加载的效果。而这种方式当Singleton类被装载了,instance不一定被初始化,因为SingletonHolder类没有被主动使用,只有通过调用getInstance方法时,才会装载SingletonHolder类,从而实例化instance

public class Singleton {  
    /**
     * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
     * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
     */  
    private static class SingletonHolder {  
        private static Singleton instance = new Singleton();  
    }  
  
    private Singleton() {  
    }  

    public static  Singleton getInstance() {  
        return SingletonHolder.instance;  
    }  
}

枚举,不延迟加载,线程安全

这种实现方式还没有被广泛使用,但这是实现单例模式的最佳方式。它更加简洁,不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过Java5之后才加入枚举特性

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}  

本文仅仅介绍了单例模式及其实现方式,推荐学习【创建型模式四】单例模式(Singleton),写的很深入详细

参考:单例模式

你可能感兴趣的:(单例(Singleton)模式)