JavaEE——单例模式

编程中为了保证可读性较高,编程大佬们根据经验设计了许多的编程模式,按照这些模式来编程,可以使我们的代码更加美观易读。而其中运用最广泛的设计模式为单例模式

单例模式也是常考的设计模式之一。

单例模式指的是某个类在程序中只存在唯一一份实例, 而不会创建出多个实例。

首先我们看一个单例模式示例:

class Singleton {
    private static Singleton instance = new Singleton();//创建实例对象
    public static Singleton getInstance() {
        return instance;//获取唯一实例对象的方法
    }
    private Singleton() {};//限制从外部new对象
}

单例模式分为两种:饿汉模式懒汉模式

饿汉模式指的是在类加载时就创建好实例对象,也就是上述示例。

显然,饿汉模式的效率不高。即使我们用不到这个对象,它依然会创建并占用资源。

因此,相对于饿汉模式,懒汉模式就避免了这个问题。懒汉模式只有在需要用到该对象时才创建实例对象,用不到则不创建:

class SingletonLazy {
    private static SingletonLazy instance = null;//唯一实例对象
    public static SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
    private SingletonLazy() {};
}

单线程操作下,懒汉模式没有问题,但是在多线程操作下,就要注意线程安全问题了。

对于饿汉模式,因为只涉及到读操作,因此不用考虑线程安全问题;而懒汉模式涉及到了写,为了保证写操作的原子性,通常的做法是加锁。

但是问题来了,加锁是加在if前还是if后呢?——一定是加在if的前面的。

假如加在if的后面,即:

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

这时有两个线程t1和t2,假如t1拿到了锁,t2阻塞,但是t1 new对象后,t2又会拿到锁,也会new对象。那么这个锁加的就没有意义了。

但是仅仅把锁加在if前面也是不行的,我们需要再套一层if语句,因此正确的懒汉模式写法是这样的:

class SingleLazy {//懒汉模式
    private static volatile SingleLazy instance = null;//加volatile防止指令的重排序

     public static SingleLazy getInstance() {
        if (instance == null) {//判断是否需要加锁
            synchronized (SingleLazy.class) {
                if (instance == null) {//判断是否创建对象
                    instance = new SingleLazy();
                }
            }
        }
        return instance;
    }
    private SingleLazy() {}
}

如果不理解的话,可以想象一下这样的场景:

A和B这两个人同时喜欢C,都想要跟C表白。他们想要表白就要先确定C有没有对象,没有对象再去。恰好呢C没有对象,于是A和B都想要去表白。但是表白肯定有先后顺序,假设A抢占先机,先进行表白,那么B准备表白时看到A在表白,就只能先等着。等到A结束了,B才能去,但是B表白前又要重新确定C是否有对象,否则就是纯纯的了。

你可能感兴趣的:(java,开发语言)