Chapter5 单件模式

2019-07-23  本文已影响0人  小麻巧吃西瓜

单件模式的经典实现:

public class Singleton {
        //利用一个静态变量来记录Singleton类的唯一实例
    private static Singleton uniqueInstance;
        //构造方法声明为私有
    private Singleton() {}
       
        //若uniqueInstance为空,则不存在实例,则利用私有的构造器产生一个实例,
        //并将它复制到uniqueInstance静态变量中;若不为空,则说明已经有了实例,直接返回。
    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
 
    // other useful methods here

}

注意,如果我们不需要这个实例,就永远不会产生,这就是“延迟实例化”。

线程不安全。


定义:

确保一个类只有一个实例,并提供一个全局访问点。

类图:

经典单件模式存在问题,它是线程不安全的。当两个或以上调用getInstance()方法的时候可能出现线程不安全的问题。


处理线程不安全的方法:

使用synchronized关键字

getInstance()方法改为:

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

该方法的不足之处在于:同步会降低性能,我们只需要第一次执行getInstance()方法的时候同步。这个方法使得每次调用这个方法都会同步,比较累赘。

解决方法:

  • 如果可以接受同步带来的性能影响,则直接忽略它。
  • 使用“急切”创建实例。
public class Singleton {
    private static Singleton uniqueInstance = new Singleton();
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        return uniqueInstance;
    }
    
    // other useful methods here

}

JVM加载这个类时马上创建唯一的单件实例,保证任何线程访问uniqueInstance静态变量之前,一定先创建此实例。前提是程序总是创建并使用单件实例,或者在创建和运行时负担不太繁重。

  • 用“双重检查加锁”,首先检查是否实例已经创建了,如果尚未创建,“才”进行同步,这样一来,只有第一次才会同步。
public class Singleton {
    private volatile static Singleton uniqueInstance;
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        //检查实例,如果不存在,就进入同步区块
        if (uniqueInstance == null) {
            synchronized (Singleton.class) {
                //进入区块后,再检查一次。如果仍是null,才创建实例
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

volatile关键字可以从可见性和有序性两方面保证线程安全。(此方法不适用于Java 5再之前的版本)


  • 单件模式确保程序中一个类最多只有一个实例。
  • 单件模式也提供访问这个实例的全局点。
  • 单件模式需要私有的构造器,一个静态变量和一个静态方法。
  • 确定在性能和资源的限制条件下,小心选择单件模式以解决多线程问题。
上一篇下一篇

猜你喜欢

热点阅读