设计模式学习-单例模式

2018-11-10  本文已影响0人  most_xiaoya

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

单例模式要素:
a)私有构造方法
b)私有静态引用指向自己实例
c)以自己实例为返回值的公有静态方法

一般要实现一个单例 最简单的方式:

public class SingleInstance {
    private static SingleInstance instance;
    private SingleInstance() {
    }
    public static SingleInstance getInstance() {
        if (null == instance)
            instance = new SingleInstance();
        return instance;
    }
}

但是这样会有一个问题,当多个线程同时调用 getInstance() 方法时,可能会产生多个instance 实例,因此这种方式并不是真正的单例。
为了解决线程安全问题,我们只需要在getInstance() 方法上使用synchronized 关键字给线程加锁即可。

public class SingleInstance {

    private static SingleInstance instance;

    private SingleInstance() {
    }

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

synchronized 的作用是加锁,当多个线程同时调用getInstance() 时,只有一个线程能进入,其他线程会等待进入的线程出来之后在一一进入,这样就能保证instance 实例是唯一的。这才是真正的单例。
不过这并不是完美的解决方案,只要是锁,必然有性能损耗问题。而且对于上面的代码,其实我们只需要在线程第一次访问时加锁即可,之后并不需要锁,锁给我们带来了系统资源浪费。

上面两种方式都是在getInstance() 方法中创建实例,也就是说在要调用的时候才创建实例,这种方式被称为“懒汉式”,英文名,叫 lazy loading,也就是延迟加载。
新的解决方案是not lazy loading,在类加载时就创建好了实例:

public class SingleInstance {

    private static SingleInstance instance = new SingleInstance();

    private SingleInstance() {
    }

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

这种方式就可以保证实例唯一。

除了上面的几种方式,还有一种叫 double-checked locking (双重检查加锁)
这种方式主要用到两个关键字volatile 和 synchronized,代码如下:

public class SingleInstance {

    private volatile static SingleInstance instance;

    private SingleInstance() {
    }
    public static SingleInstance getInstance() {

        if (instance == null) {
            synchronized (SingleInstance.class) {
                if (instance == null) {
                    instance = new SingleInstance();
                }
            }
        }
        return instance;
    }
}

volatile 关键字简单来说就是可以保证instance变量在被其中一个线程new出来时,其他线程可以立即看到结果并正确的处理它。

总结:感觉平时一般可以直接用

public class SingleInstance {

    private static SingleInstance instance = new SingleInstance();

    private SingleInstance() {
    }

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

就可以满足需求了。ok 单例就说到这儿了,优点儿?
优点就是使用单例模式,对象在内存中只有一个实例,并且无需频繁的创建和销毁对象,大大的减少了性能的损耗。

上一篇下一篇

猜你喜欢

热点阅读