设计模式之单例模式(一)

设计模式之单例模式(一)

导语: 今天在官网学习网络访问框架Volley中, google推荐我们在创建RequestQueue 对象时使用单例模式,之前也看过一些单例模式讲解的文章,还是不够熟练,在这里总结下,方便自己以后能快速复习;

单例模式简介

单例模式 ,英文名称 Singleton pattern,常用的软件设计模式。
数学与逻辑学中,singleton定义为“有且仅有一个元素的集合”
单例模式最初的定义出现于《设计模式》(艾迪生维斯理, 1994):“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”
Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

综上所述,Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。

一,单例模式的几种常见写法

1懒汉式,线程不安全(很少使用)

这是最简单的懒汉单例模式,致命的是在多线程不能正常工作。

public class Singleton {
    //定义一个变量类存储创建好的实例对象 默认为空
    //因为需要在静态方法中访问 加上static 修饰符
    private static Singleton instance =null;

    //私有化构造方法 防止外部创建对象
    private Singleton() {
    }

    //提供一个类静态方法返回单例对象 可以全局访问
    public static Singleton getInstance(){
        //懒就在这 当第一次有方法访问才创建实例
        //但是之后不会初始化对象
        if (instance==null){
            instance=new Singleton();
        }
        return instance;
    }
}

2.懒汉式,线程安全(很少使用)

使用关键字synchronized同步锁实现同步控制,变成线程安全。这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。

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

3.饿汉式(常用)

这种方式基于java虚拟机类加载机制,static变量只会在类装载的时候初始化一次,并且多个实例共享内存区域,避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载。

public class Singleton{
    //在自己内部定义自己的一个实例,只供内部调用
    private static final Singleton instance = new Singleton();
    private Singleton(){
        //do something
    }
    //这里提供了一个供外部访问本class的静态方法,可以直接访问
    public static Singleton getInstance(){
        return instance;
    }
}

4.双重校验锁 , 线程安全的懒汉式单例模式(有需求时使用)

双重检查加锁: 即线程安全又能够性能不受太大的影响。在开源的greenrobot的EventBus中,EventBus类就采用这样的双重检查加锁的单例模式。

public class SynSingleton {
    //对保存的对象 添加volatile关键字
    //volatile 修饰的变量值 不会被本地线程缓存 
    //所有的操作都是直接操作共享内存 保证多个线程能够正确的处理该变量 
    private volatile static SynSingleton instance = null;

    //私有化构造方法 防止外部创建对象
    private SynSingleton() {
    }

    //提供一个类静态方法返回单例对象 可以全局访问
    public static SynSingleton getInstance() {
        //先检查实例是否为空 不为空进入代码块
        if (instance == null) {
            //同步块 线程安全地创建实例
            synchronized (SynSingleton.class) {
                //再次检查实例是否为空 为空才真正的创建实例
                if (instance == null) {
                    instance = new SynSingleton();
                }
            }
        }
        return instance;
    }
}

5. 静态内部类(推荐使用)

  • 实现的代码思路就是,用静态初始化器的方式,由虚拟机保证线程安全。用类级内部类负责创建实例,只要不使用到这个类级内部类就不会创建实例。两者结合就实现了延迟加载和线程安全。
public class HolderSingleton {
    /**
     * 类级内部类 也就是静态的成员式内部类 该内部类的实例与外部类的实例没有依赖
     * 而且只有被调用的时候才会被装载,从而实现延迟加载
     */
    private static class SingletonHolder{
        //静态初始化器 由虚拟机保证线程安全
        private static HolderSingleton INSTANCE= new HolderSingleton();
    }

    private HolderSingleton() {
    }

    public static HolderSingleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

6.枚举

public enum  EnumSingleton {
    /**
     * 枚举元素 它就代表单例的一个实例
     */
    uniqueInstance;

    public void setUniqueInstance(){
        //对应普通单例的对象方法或者是功能操作
    }

}

二,单例模式在Volley中的使用

Volley对于只使用一次的网络请求,常用Volley.newRequestQueue(this)方法来实例化RequestQueue对象。而对于需要频繁使用,贯穿整个生命周期的Request,Google推荐我们使用单例模式来创建一个类包含RequestQueue类对象,以及其他方法。这样我们实例化整个类的时候,既保证了也能保证单例类MySingleton是唯一的,成员变量RequestQueue对象也是唯一的。

这里使用的是第二种“懒汉式,线程安全”的单例模式。

public class MySingleton {
    private static MySingleton mInstance;
    private RequestQueue mRequestQueue;
    private static Context mCtx;

    private MySingleton(Context context) {
        mCtx = context;
        mRequestQueue = getRequestQueue();
    }

    public static synchronized MySingleton getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new MySingleton(context);
        }
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            // getApplicationContext() is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
        }
        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req) {
        getRequestQueue().add(req);
    }
}

那么如何实例化RequestQunce呢

// Get a RequestQueue
RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).getRequestQueue();

资料参考:
1.设计模式-单例模式(Singleton)各种写法和分析比较
2.单例模式的七种写法
3.单例模式_百度百科

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值