《Head First 设计模式》读书笔记——单例模式

今天来看单例模式,是类结构比较简单的一个设计模式,事实上,他只有一个类。哈哈哈,那我们接下来就看看吧。

public class Singleton {
    private static Singleton uniqueInstance;
    
    private Singleton() {}

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

这里面先是定义了一个私有化的本类属性,接着是一个私有化的构造方法,只有本类内才能调用构造方法,下面是重点,通过 getInstance() 方法使得外面的类能获得本类对象,首先是一个判断,如果本类属性 uniqueInstance 为空,则实例化一个属性,否则直接返回这个属性,以保证我们的对象只有一个。

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

getInstance() 方法可以延迟我们这个类的实例化,这个 uniqueInstance 类属性是这个类唯一的实例化对象,只有当第一次使用到这个的对象时,也就是第一次调用 getInstance() 方法时才会 uniqueInstance 实例化,以后再用这个类时,直接返回这个属性。

但这段代码也不是无懈可击的,多线程的情况下,使用这段代码简直是灾难,现在我们看看如何解决:

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

就是通过增加 synchronized 关键字到 getInstance() 方法中,迫使每个线程在进入到这个方法之前要等到其他线程离开该方法。但是这样还是有问题,首先是同步会降低性能,其次,我们只有在第一次实例化这个属性时才需要设置同步,一旦设置好 uniqueInstance 就不需要同步了,所以后面的每一次同步都是多余的步骤。

所以我们可以在 JVM 加载这个类时就做好实例化工作,看下面的代码:

public class SingletonFirst {
    private static SingletonFirst uniqueInstance = new SingletonFirst();
    
    private SingletonFirst() {}
    
    public static SingletonFirst getInstance() {
        return uniqueInstance;
    }
}

这样我们在 JVM 加载这个类时,就可以马上创建唯一的单件实例。JVM 保证任何线程访问这个静态变量之前都会先创建这个实例。

还有一种方法,使用「双重检查锁」,在 getInstance() 减少使用同步,代码如下:

public class SingletonDouble {
    private volatile static SingletonDouble uniqueInstance;
    
    private SingletonDouble() {}
    
    public static SingletonDouble getInstance() {
        if (uniqueInstance == null) {
            synchronized (SingletonDouble.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new SingletonDouble();
                }
            }
        }
        return uniqueInstance;
    }
}

这个方法,我们可以大大减少时间消耗,首先检查实例,如果没有,进入同步区块,再一次检查实例,如果没有才创建,注意,同步区块这段代码,我们只会执行一次,只有第一次才会同步。双重检查锁机制不适用于 1.4 及更早的版本。

好了,所有单例模式的实现方式就都写完,好好记得吧。

发布了26 篇原创文章 · 获赞 2 · 访问量 2328

猜你喜欢

转载自blog.csdn.net/qq_42909545/article/details/104895625