设计模式笔记—单例模式

单例模式定义:
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

使用场景

     确保某一个类有且只有一个对象的场景,避免产生多个对象,消耗过多的资源,或者某一种类型的对象只应该有且只有一个。例如,创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源,这时就要考虑使用单例模式。

关键点

1 构造函数不对外开放,一般为Private;

2 通过一个静态方法或者枚举返回单例类对象;

3 确保单例类的对象有且只有一个,尤其是在多线程环境下;

4 确保单例类对象在反序列化时不会重新构建对象;

如何使用?
一般Singleton模式通常有两种形式:

第一种形式(饿汉式):

 public class Singleton {
  private Singleton(){}

  //注意这是private 只供内部调用
  private static Singleton instance = new Singleton();

     //这里提供了一个供外部访问本class的静态方法,可以直接访问  
  public static Singleton getInstance() {
    return instance;   
   } 
} 

第二种形式(懒汉式):

public class Singleton {
  private static Singleton instance = null;
  public static synchronized Singleton getInstance() {
  //这个方法比上面有所改进,不用每次都进行生成对象,只是第一次     
  //使用时生成实例,提高了效率!
  if (instance==null)
    instance=new Singleton();
  return instance;   }
}
使用Singleton.getInstance()可以访问单态类。

上面第二中形式是懒汉式,也就是说第一次调用时初始Singleton,以后就不用再生成了。

注意到懒汉式形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例。一般认为第一种形式要更加安全些。

懒汉式优点:只有在使用时才会被实例化,在一定程度上节约了资源;缺点:第一次加载时需要及时进行实例化,反应稍慢,最大的问题是每次调用getInstance都进行同步,造成不必要的同步开销。

-----------------------------------------------------------

多线程时的单例

//解释一下锁lock语句的含义,lock是确保当一个线程位于代码的临界区
//时,另一个线程不进入临界区.如果其他线程试图进入锁定的代码,则它将一直等待
//(即被阻止),直到该对象被释放。
public class Singletons {
private static Singletons instance;
//程序运行时创建一个静态只读的进程辅助对象
private static readonly object syncRoot=new object();
public Singletons(){}
public static Singletons GetInstance(){
//在同一个时刻加了锁的那部分程序只有一个线程可以进入
lock(syncRoot)
{
if(instance==null){
instance=new Singletons();
}
}
return instance;
}
}

---------------------------------------------------------------

双重检查(DCL):

第一种写法:

public class Singleton {
private static Singleton instance;
private static readonly object syncRoot=new object();
private Singleton(){}
public static Singleton GetInstance(){
//先判断实例是否存在,不存在再加锁处理
if(instance==null)
{
lock(syncRoot)
{
if(instance==null)
{
instance=new Singleton();
}
}
}
return instance;
}
}
//为什么lock里面还需要做一次instance判断?在lock机制下,两个
//线程只有一个进入,另一个排队等候,在第一个进入并出来后,第二个才能进入,
//此时如果没有了第二重的instance是否为null的判断,则第一个线程创建了实例后
//而第二个线程进入后还是可以继续再创建新的实例,这就没有达到单例的目的。
第二种写法:

public class Single {
	public static Single s=null;
	private Single(){
	}
	public static synchronized Single getInstance(){
		if(s==null){
			synchronized (Single.class) {
				if(s==null){
				s=new Single();
				}
			}
		}
		return s;
	}
}
分析:可以看到getInstance方法对s进行了两次判空:第一层判断是为了避免不必要的同步,第二层判断则是为了在null的情况下创建实例。假如线程执行到了s=new Single()语句,它大致做了3件事情:1)给Single的实例分配内存;2)调用Single()的构造函数,初始化成员字段;3)将s对象指向分配的内存空间(此时s就不是null了).

DCL的优点:资源利用率高,第一次执行getInstance时单例对象才会被实例化,效率高。缺点:第一次加载时反应稍慢。

lock与synchronize的区别是什么?

解答:参考

Android的应用

在Glide图片加载框架中的应用:

public class RequestManagerRetriever implements Handler.Callback {
 private static final RequestManagerRetriever INSTANCE = new RequestManagerRetriever();
  // Visible for testing. 注:此构造方法只在本包中可见
    RequestManagerRetriever() {
        handler = new Handler(Looper.getMainLooper(), this /* Callback */);
    }
    public static RequestManagerRetriever get() {
        return INSTANCE;
    }
}

在Android FrameWork层中的应用:

ActivityThread() {
        mResourcesManager = ResourcesManager.getInstance();
    }
** @hide */
public class ResourcesManager {
 private static ResourcesManager sResourcesManager;
 public static ResourcesManager getInstance() {
        synchronized (ResourcesManager.class) {
            if (sResourcesManager == null) {
                sResourcesManager = new ResourcesManager();
            }
            return sResourcesManager;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值