设计模式之单例模式

什么是单例模式?

The Singleton Pattern 确保一个类只能有一个实例,并且提供给全局去使用它。

  • 我们创造一个类并且使它自己去管理自己的一个单例,我们也得阻止其它的类里面声称这个类的实例,如果获得一个实例,必须通过这个类本身去创建。
  • 我们需要给全局提供一个入口去获得这个类的实例:当我们需要这个实例,只是查询该类,该类就会返回一个单例。

为什么要使用单例模式?

有许多的对象,往往都仅需要一个实例,比如线程池、缓存、对话框、处理参数和注册设置的对象、日志对象和一些扮演驱动设备去服务的对象,比如打印机和显卡等,像这些类型的对象,如果我们实例化多于一个这样的实例,我们会运行出这样一系列的错误,像错误的编码方式,内存溢出,前后不一致的结果等等。
下面看一下单例模式的实现:

public class Singleton {

    private static Singleton uniqueInstanse;

    private Singleton() {

    }

    public static Singleton getInstance() {
        if (uniqueInstanse == null) {
            uniqueInstanse = new Singleton();
        }
        return uniqueInstanse;
    }
}

关于jvm

我们有两个线程,同时各自处理这段代码

ChololateBoiler boiler = ChocolateBoiler.getInstance();
fill();
boil();
drain();

程序执行getinstance()方法和给唯一实例的赋值的顺序是不确定的。所以代码执行的交错可能产生两个对象。
因此,怎么解决这个问题呢?如下代码
处理多线程问题

public class Singleton {
private static Singleton uniqueInstance;
privte Singleton() {}
pulbic static synchronized Singleton getInstance() {
    if (uniqueInstance == null) {
        uniqueInstance = new Singleton();
    }
    return uniqueInstance;
}

这个解决方案时正确的,不过,这个同步关键字只有在第一次执行这段代码时才会有作用,换句话说,不做使用当我们已经有这个唯一实例时,就不需要这个synchronize方法,在第一次之后,synchronization就成为了不必要的花销。
那怎么改善一下多线程问题?

  • 当应用对我们获得实例的性能不挑剔的时候,我们就不用做任务处理。
  • 在把lazily created 变成eagerly created。
public class Singleton {
    private static Singleton uniqueInstance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return uniqueInstance;
    }
}

使用这个实现,我们依赖JVM当类加载的时候去创建唯一单例实例,在任何线程使用它的时候,JVM确保唯一实例的创建。

  • 使用双重检查锁定去处理使用synchronization in getInstance();
public class Singleton {
    private volatile static Singleton uniqueInstance;
    private Singleton() {}

    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            synchronized (this) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

当单例实例话的时候,volatile 关键字确保在多线程情况下正确地处理唯一实例变量。
当使用getinstance() 存在性能问题时,使用这个方法可以彻底地降低花销。不过这个方法不能用在java1.4或者之前的版本。
单例模式讲到这里差不多就结束了。
为什么不能仅仅创建类的时候全部方法或者变量定义成静态的?,这个根单例不一样吗?
因为静态的方式初始是在java中处理,这些会变的非常肮脏,尤其是设计多个类的时候。通常这个方案使问题变得微妙,很难发现问题,当涉及到初始化顺序。除非有操作需要你去用这种反式去实现单例,最好使停留在面相对象的世界。在java中,全局变量是基于静态的对象引用。有很多不利的因素使用全局变量这种方式。全局变量意在鼓励开发者去污染命名空间对一些简单的对象,而单例模式不鼓励去这样做。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值