上个世纪九十年代实行计划生育,我差点成了牺牲品(不开玩笑),郭嘉之所以实行计划生育是因为当时人口爆炸式增长,郭嘉害怕这种增长导致资源短缺。

这里用到对象也是成立的,比如说一个桌面应用的工具栏窗口,如果点击一次出现一个工具栏,用户多次点击的话就会出现很多个工具栏,会造成资源的浪费。

所以这里就要运用一种设计模式:单例模式。这个模式也是十分的常用的设计模式。

设计模式比较简单,不用画UML类图了。

单例模式简而言之就是一个类只有一个对象,而且类外部无法利用构造器实例化一个对象,这就要求我们设置构造器方法为私有,不允许外部访问。

那么我们不能用外部访问构造器就只好内部访问构造器了,所以要在内部实例化对象。

单例模式一般有一个内部成员是这个单例模式类的对象,内部也有一个getInstance()方法用来获取这个唯一的对象。

而饿汉式的单例模式是这个类在初始化后就生成这个对象:

public class HungrySingleton {
    private static HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton() {

    }

    public static HungrySingleton getInstance()
    {
        return hungrySingleton;
    }
}

懒汉式的单例模式则是在我们需要用这个类的单例模式才创建对象,但是这个时候问题来了,如果是多线程情况,多个线程同时调用这个方法可能就会出现创建了多个对象的情况,

这个时候就需要向方法中上锁了,而上锁有两种上锁方式:

/**
 * @author 陈柏宇
 * 单例模式
 * 懒汉式单例模式,充分考虑多线程情况并优化效率
 */

public class LazySingleton {
    private static LazySingleton singleton;

    private LazySingleton() {

    }

    public  static LazySingleton getSingleton() {

        /*
        方式一:
        效率稍差
         */

//        synchronized (Singleton.class){
//            if (singleton == null){
//                singleton = new Singleton();
//            }
//        }

        /*
        方式二:
        效率高
         */
        if(singleton == null) {
            synchronized (LazySingleton.class) {
                if(singleton == null) {
                    singleton = new LazySingleton();
                }
            }
        }
        return singleton;
    }
}

我们来观察方式一:

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

这个方法可以确保线程安全但是效率低下,因为如果同时有多个线程调用而且没有这个对象的话只有一个线程能拿到锁,然后其他线程全部在外面等待,这样效率太低了。

方式二:

if(singleton == null) {
    synchronized (LazySingleton.class) {
        if(singleton == null) {
            singleton = new LazySingleton();
        }
    }
}
return singleton;

方式二相对来说效率高,如果没有这个对象实例则才能拿到锁,拿到锁后还要进行一次判断,因为如果同时有两个线程通过第一次if判断,那么假设线程1拿到了锁,并且创建了对象,

线程二在拿到锁后如果没有if判断则又创建了一次对象,如果有if判断就不用创建对象了,所以这里要进行双重锁定。