设计模式(5)--单例模式

什么是单例模式

  在一些场合下,我们有可能希望一个对象仅存在一个,例如线程池、缓存等,可能是因为这些对象创建一次很消耗性能,也可能是实际需要,这些都需要结合一定的实际场景。总的来说,就是无论用户怎么得到这个对象,它都是唯一一个,即为同一对象。

如何实现单例模式

  首先我们先写一个平常类,如Simple

public class Simple {

    private String desc;

    public Simple(String desc) {
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }
}

  可以很清楚看到这里包含了一个构造方法,且该方法作用域为public。

  假如改成private,会怎么样呢?在其他类中肯定就无法new出这个对象了。

  没有办法new出对象,那就不能随便在其他类中创建该类了,这个类的创建只有自己来负责创建,然后在通过一个静态方法来返回这个对象,感觉好像符合需求。

  修改实例代码:

public class Simple {

    private String desc;

    private static Simple instance;

    private Simple(String desc) {
        this.desc = desc;
    }

    public static Simple getInstance(String desc) {
        if (instance == null) {
            instance = new Simple(desc);
        } else {
            instance.setDesc(desc);
        }
        return instance;
    }

    private void setDesc(String desc) {
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }
}

  相信你已经迫不及待的想测试下你的代码了,可以参考下面示例:

public class Test {
    public static void main(String[] args) {
        System.out.println(Simple.getInstance("v1"));
        System.out.println(Simple.getInstance("v2"));
    }
}

  运行后你会发现两个输出是一致的。

  但是这种单例模式是存在线程安全问题的,当多个线程调用Simple.getInstance()方法是就会出现问题。为什么呢?比如现在有两个线程,分别为线程a和线程b,线程a调用这个方法,运行到if判断语句中了,但是还没有创建这个对象,被要求沉睡10s,此时线程b也运行到if判断这里了,这时候获取到的对象肯定还是为空,那么它也会创建对象了。这时候就会创建出两个不一样的对象,自然就不符合要求呢?

  既然getInstance这个方法可能会被同时调用,那么就不在这个方法内进行判断,直接在声明是就创建,然后这个方法直接返回对象就好了。

  示例如下:

public class Simple {

    private String desc;

    private static Simple instance = new Simple("default");

    private Simple(String desc) {
        this.desc = desc;
    }

    public static Simple getInstance(String desc) {
        instance.setDesc(desc);
        return instance;
    }

    private void setDesc(String desc) {
        this.desc = desc;
    }

    public String getDesc() {
        return desc;
    }
}

  红色标记表示修改处,这样就不存在线程安全了,但是有没有什么缺陷呢?

  答案是有,这种方法就是无论你是否使用这个方法,这个类对象都会被创建,而第一种则是只有使用时才会进行创建,也可以被称为“延迟加载”。至于用哪一种根据实际项目需求,但是不要忘了第一种方法存在线程安全问题,当然这个是可以解决的,怎么解决可以自己去搜索下。

  下一篇将介绍命令模式,如果你对这篇博客有什么见解或疑问,可以进行留言哦

posted @ 2017-04-28 15:19  逆倒尘光  阅读(188)  评论(0编辑  收藏  举报