设计模式之单例模式(Singleton Pattern)

    单例模式:确保一个类只有一个实例,并提供一个全局访问点。单例可以延迟实例化(lazy instantiate)。

 

// 经典的单件模式实现
public class Singleton {
    /* 利用一个静态变量来记录Singleton类的唯一实例 */
private static Singleton uniqueInstance;
// 这里是其他的有用实例化变量
private Singleton() {
    /* 把构造器声明为私有的,只有在Singleton类内才可以调用它*/
}
/* 用getInstance()方法实例化对象,并返回这个实例 */
public static Singleton getInstance() {
    if (uniqueInstance == null) {
    /* 如果我们不需要这个实例,它就永远不会产生,这就是延迟实例化*/
    uniqueInstance = new Singleton();
}

return uniqueInstance;
}
// 这里是其他有用的方法
}

    有些对象我们只需要一个,例如线程池、缓存、处理偏好设置和注册表的对象、日志对象、充当打印机、显卡等设备的驱动程序的对象。而单例模式给我们了一个全局的访问点,和全局变量一样方便,又没有全局变量的缺点,如果将对象赋值给一个全局变量,那么你必须在程序一开始就创建好对象,如果这个对象非常耗资源,而程序在这次的执行过程中又一直没有用它,这就形成了浪费。

    单例模式中的多线程问题:两个线程有可能会创建两个实例,那么该如何处理这种情况呢:

    A.只要把getInstance()变成同步(synchronized)方法(会降低性能,其实只有第一次执行此方法时,才需要同步,如果getInstance()的性能对应用程序不是很关键,就用这种方法)

 

public class Singleton {
    private static Singleton uniqueInstance;

    // 其他有用的实例化的变量
   Private Singleton() {}

   Public static synchronized Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }

        return uniqueInstance;
   }
// 其他有用的方法
}

   B. 使用“急切”创建实例(饥渴式),而不用延迟实例化(懒汉式)的做法

 

public class Singleton {
    /* 在静态初始化器(static initializen)中创建单件 这保证了线程安全(thread safe)*/
private static final Singleton uniqueInstance = new Singleton();

public static Singleton getInstance() {
    return uniqueInstance; // 直接返回实例
}
}

   C.用“双重检查加锁”(double-checked locking,首先检查实例是否已经创建了,如果尚未创建,才进行同步),在个getInstance()中减少使用同步:

 

public class Singleton {
    /* volatile关键字确保:当uniqueInstance变量被初始化成Singleton实例时,多个线程正确地处理uniqueInstance变量 */
private volatile static Singleton uniqueInstance;

private Singleton() {}

public static Singleton getInstance() {
    if (uniqueInstance == null) { // 检查实例,如果不存在,就进入同步区块
    synchronized (Singleton.class) {//只有第一次才彻底执行这里的代码
    if (uniqueInstance == null) {//进入区块后,再检查一次
        uniqueInstance = new Singleton();
}//Singleton.class是该类对应的字节码文件对象。
}
}

return uniqueInstance;
}

   如果使用 多个类加载器,可能导致单例失效而产生多个实例。

你可能感兴趣的:(设计模式,多线程,单例模式,同步)