单例模式

来源:互联网 发布:无线网测试软件 编辑:程序博客网 时间:2024/06/06 17:19

单例模式

回顾一下
- 工厂模式: 女娲造人
- 抽象工厂模式: 厨房,食物,吃货
- 适配器模式: 港版iphone6,充电头,转接头
- 装饰者模式: 各种女朋友
- 观察者模式: 视频网站,美剧

什么是单例模式

单例模式,顾名思义,就是被单例的对象只能有一个实例存在。单例模式的实现方式是,一个类能返回对象的一个引用(永远是同一个) 和 一个获得该唯一实例的方法(必须是静态方法)。用过单例模式,我们可以保证系统中只有一个实例,从而在某些特定的场合下达到节约或者控制系统资源的目的。

单例模式类图

在装饰者模式中,体验了不同的女朋友后,最后你只能拥有一个老婆。

  1. 饿汉模式

    最常见的单例模式之一。正如其名,很饥渴,所以一上来就需要给它新建一个实例。但这种方法有一个明显的缺点,就是不管有没有调用过获得实例的方法,每次都会创建一个实例。

    `
    //饿汉模式
    public class Wife {
    //上来就新建一个实例
    private static final Wife wife = new Wife();

        //默认构造方法    private Wife() {}    //获得实例的方法    public static Wife getWife() {        return wife;    }}

    `

  2. 懒汉模式

    最常见,最简单的单例模式之二,跟饿汉模式是好基友。顾名思义,就是一开始不新建实例,只有当它需要使用的时候,会先判断实例是否为空,如果为空才会新建一个实例来使用。

    `
    public class Wife {
    //一开始没有新建实例
    private static Wife wife;

        private Wife() {}    //需要时再建    public static Wife getWife() {        if (wife == null)            wife = new Wife();        return wife;    }}

    `

  3. 线程安全的懒汉模式
    上面的懒汉模式存在一个严重的问题,那就是如果有多个线程并行调用getWife()方法的时候,还是会创建多个实例,单例模式就失效了。

    那我们只需价格线程同步就好了是吧。(synchronized)

    `
    public class Wife {
    private static Wife;

        private Wife(){}    public static synchronized getWife() {        if (wife == null)            wife = new Wife();        return wife;    }}

    `

4.双重检查锁

上诉看似完美的解决了问题,但是它的效率不高,每次调用获得实例的方法getWife()都要进行同步,但是多数情况下是并不需要同步操作的(例如我的wife实例不为空可以直接使用的时候,就不需要给getWife()方法加同步,直接返回wife实例就可以)。所以只需要在第一次新建实例对象的时候,使用同步方法。`    //双重锁的getWife()方法    public static Wife getWife() {        //第一个检查锁,若不为空直接返回实例对象,为空才进入下一步        if (wife == null) {            synchronized(Wife.class) {                //第二个检查锁,因为可能有多个线程进入到if语句内                if (wife == null)                     wife = new Wife();            }        }        return wife;    }`

但是!!! 这还没有结束,主要问题在于wife = new Wife(),因为JVM在执行这句代码时,要做好几件事情,而JVM为了优化代码,有可能造成做这几件事的顺序不固定,从而造成错误。

这个时候我们需要给实例加一个volatile关键字,它的作用就是防止编译器自行优化代码。所以…最终双重检验锁出炉了。

`    public class Wife {        private volatile static Wife wife;        private Wife() {}        public static Wife getWife() {            if (wife == null) {                synchronized(Wife.class) {                    if (wife == null) {                        wife = new Wife();                    }                }            }        return wife;        }    }`
  1. 静态内部类
    上面的方法,实在是太复杂了,而且volatile关键字在某些老版本的jdk中无法正常工作。咋们的换一种方法,即“静态内部类”,这种方式,利用了JVM自身的机制来保证线程安全,因为WifeHolder类是私有的,除了getWife()之外没有其他方式可以访问实例对象,而且只有在调用getWife()时才会去真正创建实例对象。

    `
    public class Wife {
    private static class WifeHolder {
    private static final Wife wife = new Wife();
    }
    private Wife(){}

        public static Wife getWife() {        return WifeHolder.wife;    }}

    `

原创粉丝点击