创建型模式之一
定义:确保某个类只有是一个实例,而且自行实例化并向整个系统提供这个实例。
使用场景:避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。
优点: 减少内存的开支,可以永久驻留内存(随着应用的创建而创建,销毁而销毁)避免对同一个资源的同时操作,快捷访问等。
缺点:单例一般没有接口,扩展差,注意内存泄漏(android 如果单例持有Context对象,要传递Application Context,否则容易引起内存泄漏)。
饿汉式 :
线程安全 ,如果单例用不到 ,造成了内存的开销 .
public class HungrySingle {
private static HungrySingle mHungrySingle = new HungrySingle();
private HungrySingle() {
}
public static HungrySingle getInstance() {
return mHungrySingle;
}
}
懒汉式:
线程不安全的, 在多线程环境下, 并不能做到单例.
public class LazybonesSingle {
private static LazybonesSingle mLazybonesSingle;
//私有构造
private LazybonesSingle() {
}
//对外提供访问方法
public LazybonesSingle getInstance() {
//如果两个线程同时调永走到 ==null的时候 可能会创建两个对象
if (mLazybonesSingle == null) {
mLazybonesSingle = new LazybonesSingle();
}
return mLazybonesSingle;
}
}
懒汉式:
线程安全 ,获取实例的时候,每次都走同步,造成了不必要的开销.
public class LazybonesSingleSafe {
private static LazybonesSingle mLazybonesSingle;
private LazybonesSingleSafe() {
}
public synchronized static LazybonesSingle getInstance() {
if (mLazybonesSingle == null) {
mLazybonesSingle = new LazybonesSingle();
}
return mLazybonesSingle;
}
}
DCL(双重锁验证)式:
减少了每次同步的开销 ,还保证了懒加载 ,但是在高并发的情况下,还有可能造成多实例的存在.
public class LazyboneSingleDCL {
private static volatile LazyboneSingleDCL mLazyboneSingleDCL;
private LazyboneSingleDCL() {
}
public static LazyboneSingleDCL getInstance() {
//如果为空 进入同步 不等空 直接取走对象 减少了同步的开支
if (mLazyboneSingleDCL == null) {
//如果为空 确保只有一个线程进入
synchronized (LazyboneSingleDCL.class) {
//防止多线程 进入 再次判断如果对象不为空 直接取值
if (mLazyboneSingleDCL == null) {
mLazyboneSingleDCL = new LazyboneSingleDCL();
}
}
}
return mLazyboneSingleDCL;
}
}
静态内部类式:
java高并发,描述DCL是丑陋的,解决方案是用 静态内部类来解决.
JVM的类加载方式(虚拟机会保证一个类的初始化在多线程环境中被正确的加锁、同步), 来保证了多线程并发访问的正确性.
这种方式是一种比较完美的单例模式. 当然, 它也有其弊端, 依赖特定编程语言, 适用于JAVA平台.
public class StaticInnerClassForm {
private StaticInnerClassForm() {
}
public static StaticInnerClassForm getInstance() {
return FormHolder.INSTANCE;
}
private static class FormHolder {
private static StaticInnerClassForm INSTANCE = new StaticInnerClassForm();
}
}
以上单例,存在一种情况可以再次创建对象 反序列化 以上方法为了不让序列化创建对象 加入readResolve()方法 可以保证
枚举式:
单例,默认线程安全,任何情况下都保证对象唯一.
public enum SingletonEnum {
INSTANCE;
public void doSomething() {
}
}
容器单例式:
android的各种服务的单例使用Map来储存的.
public class SingleMap {
private static Map<String, Object> mSingMap = new HashMap<>();
private SingleMap() {
}
public void registerSingleService(String key, Object value) {
if (!mSingMap.containsKey(key)) {
mSingMap.put(key, value);
}
}
public Object getService(String key) {
//如果没有这个值的要抛出异常
return mSingMap.get(key);
}
}
########如有出入,望大佬扶正,谢谢!!!