您的位置:首页 > 编程语言 > Java开发

java设计模式--单例模式

2016-02-27 14:09 162 查看
在android实际开发中,我们经常会用到一些开源库,诸如picasso,imageLoader以及okHttp等第三方的开源框架,在这些开源库中,我们多多少少都会看到单例模式的使用,这里对单例模式做个总结。

单例模式

单例模式,顾名思义就是单例对象的类必须保证只有一个是实例的存在,而且自行实例化并向整个系统提供这个实例。

使用场景

当我们需要确保一个类只有一个对象的场景,避免多个对象消耗过多的资源,如要访问IO或者数据库等资源的时候,可以考虑使用这个模式。

单例模式的实现

下面简单介绍一下单例模式的实现方法:

1.懒汉式单例模式

之所以叫做懒汉单例,是因为我们只需要在我们需要创建这个类的对象的时候才需要进行对这个对象的实例化操作,如下述代码所示:

public class Singleton{
private static Singleton instance;
private Singleton(){}

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


这是最简单的懒汉式的实现方法,但是这种实现方法有很大的弊端,当我们如果有多个线程访问这个单例的时候,并不能保证只有一个单例对象。

举个例子,比如我们有两个线程A,B同时访问这个单例,那么A判断完后发现Instance还没实例化,就会产生一个单例,恰巧在A判断的同时B也刚好访问了,那么B获得到的信息也是instance==null,那么单例就有两个对象了

为了防止上述的问题的产生,我们引入sychronized关键字,修改后如下:

public class Singleton{
private static Singleton instance;
private Singleton(){}

public static  Singleton getInstance(){
if(instance==null){
sychronized(Singleton.class)
if(instance==null)
instance=new Singleton();
}
}
}


通过进行双重锁的判断,我们可以避免多个实例的产生,在getInstance中我们进行两次的非空判断。

1.饿汉式单例模式

饿汉单例天生就是线程安全的,我们不必学要进行多余的线程安全的判断,如下所示:

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

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


由于一开始我们就实例化了这个类,所以天生是线程安全的。

那有没有更好的方法呢,答案是有的,在《effective java》书中就为我们提供了更加安全的方法:

1.使用内部静态类实现:

public class Singleton{
private Singleton(){}

public static  Singleton getInstance(){
return SingletonHolder.instance;
}
private static class SingletonHolder{
priavte static final Singleton instance=new Singleton();
}
}


当我们第一次加载这个类的时候并不会初始化instance,只有在我们第一次调用getInstance才会,因此第一次调用getInstance会导致虚拟机加载SingletonHolder类,这种方式不仅能保证线程安全,也可以保证其唯一性,也延迟了单例的实例化,所以推荐使用

2.枚举单例

public enum Singleton{
INSTANCE;
public void done(){

}
}


使用枚举的原因是因为枚举单例最大的优点是简单编写,而且默认枚举单例的创建是线程安全的,在任何情况下他都是一个单例。

总结:

这里优先推荐使用枚举类型,考虑到上述的单例模式除了枚举类型以外,其余在一种特殊的情况下会进行重新创建对象,那就是反序列化~

使用单例模式的优缺点:

优点:

由于单例模式在内存中只存在一个单例,减少内存开支特别是一个对象需要平凡创建和销毁的时候。

缺点:

单例模式一般没有借口,拓展很困难。

单例对象如果持有context对象,很容易引起内存的泄露,此时需要注意传递给单例的context最好是applicationcontext
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: