设计模式之创建型(1)——单例模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/M_sdn/article/details/86364551

定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

三种写法:

(1)懒汉式

public class SingletonLazy {
    private static SingletonLazy instance = null;
    private SingletonLazy () {}

    public static SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
}

优点:使用时才创建,节约资源

缺点: 线程不安全,因为多线程环境下,new SingletonLazy()可能会执行多次。

改进1:给getInstance()方法加锁。

public class SingletonLazy {
    private static SingletonLazy instance = null;
    private SingletonLazy () {}

    public synchronized static SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
}

问题:多线程环境下,虽然能保证单例,但是每个线程进入getInstance() 方法时,都会挂起其他的线程,即便SingletonLazy已经被实例化了,方法也不是立即返回,而synchronzized是有时间代价的,所以效率不高。

改进2:双重检查

public class SingletonDoubleCheck {
    private static SingletonDoubleCheck instance = null;
    private SingletonDoubleCheck () {}

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

优点:多线程环境下

1. 执行getInstance()方法时,不需要阻塞,如果SingletonDoubleCheck已经被创建,则方法迅速返回对象实例。这是第一层检查的的作用。

2. 只在SingletonDoubleCheck未被初始化的时候才加锁,这是比“改进1”效率高的地方。第二层检查的作用是保证单例。

扫描二维码关注公众号,回复: 4898919 查看本文章

问题:new SingletonDoubleCheck()不是一个“原子操作”,就是说这个操作需要n步才能完成,这里涉及一个JVM的话题——指令重排序,这就可能导致先修改了instance的值,再执行真正的构造方法。所以,还是有可能出现一个线程未出这个语句块时,另一个线程进入。(笔者对这个地方,还不太能解释清楚,先做个标记,后面完善)

改进3:加volatile

public class SingletonDoubleCheck {
    private volatile static SingletonDoubleCheck instance = null;
    private SingletonDoubleCheck () {}

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

(2)饿汉式

public class SingletonHungry {
    private static SingletonHungry instance = new SingletonHungry();
    private SingletonHungry () {}

    public static SingletonHungry getInstance() {
        return instance;
    }
}

优点:线程安全,由JVM load机制保证

缺点:过早浪费资源 

(3) 静态内部类式(推荐使用)

public class Singleton {
    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
    
    private Singleton() {}

    private static class SingletonHolder {
        private static Singleton instance = new Singleton();
    }
}

优点:在使用时才创建实例对象,JVM机制。

猜你喜欢

转载自blog.csdn.net/M_sdn/article/details/86364551