美文网首页
单例模式

单例模式

作者: CodingSnail | 来源:发表于2017-12-06 13:26 被阅读0次
微信图片_20171218200747.jpg

目前代码已经上传到GitHub,里面有设计模式系列的整个代码
GitHub 设计模式地址

1、什么是单例模式?

确保一个类只有一个实例,而且自行实例化并向整个系统提供一个全局访问点。

2、单例模式的优点:

在内存中只有一个对象,节省内存空间。
避免频繁的创建销毁对象,可以提高性能。
避免对共享资源的多重占用。
可以全局访问。

3、单例模式的常见的写法

饿汉、懒汉、懒汉安全、DCL、枚举、容器、静态内部类

饿汉模式

/**
 * Created by Snail on 12/6/2017 11:02 AM
 * Contact with slowsnail0223@gmail.com
 * 饿汉模式
 */
public class HungrySingleton {

    private static final HungrySingleton instance = new HungrySingleton();

    private HungrySingleton() {
    }

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

线程安全的,但是声明的时候已经初始化了,对于一些不是很常用的,会消耗一定的资源。

懒汉模式

/**
 * Created by Snail on 12/6/2017 10:54 AM
 * Contact with slowsnail0223@gmail.com
 * 懒汉模式
 */
public class LazySingleton {

    private static LazySingleton instance;

    private LazySingleton() {}

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

懒汉模式 只有使用时才会实例化,在一定程度上节约了资源,缺点是第一次加载时需要及时进行实例化,反应稍慢,线程不安全

饿汉安全模式

/**
 * Created by Snail on 12/6/2017 10:56 AM
 * Contact with slowsnail0223@gmail.com
 * 懒汉模式 方法同步锁
 */
public class LazySafetySingleton {

    private static LazySafetySingleton instance;

    private LazySafetySingleton() {
    }

    public static synchronized LazySafetySingleton getInstance() {
        if (instance == null) {
            instance = new LazySafetySingleton();
        }
        return instance;
    }
}

getInstance()添加了synchronized关键字,即使instance已经初始化了,那么下次在访问的时候还是会进行同步,这样会消耗不必要的资源。

DCL模式

/**
 * Created by Snail on 12/6/2017 11:01 AM
 * Contact with slowsnail0223@gmail.com
 * Double Check Lock
 */
public class DclSingleton {

    private volatile static DclSingleton instance = null;

    private DclSingleton() {
    }

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

DCL方式实现单例的优点是既能在需要时才初始化单例,又能够保证线程安全,且单例对象在初始化后调用getInstance()不进行同步锁,但是也有需要注意的地方。
instance = new DclSingleton()编译成汇编指令的时候,大概做了三件事:
1、给DclSingleton 的实例分配内存
2、调用DclSingleton()的构造函数,初始化成员字段
3、将instance对象指向分配的内存空间
但是由于Java编译器允许处理器乱序执行,上面的2和3的顺序是无法保证的,可能是1-2-3,也可能是1-3-2,如果是后者,并且在3执行完毕,2执行之前,被切换到线程B上,这时候instance在A内已经制定过了第三点,instance已经是非空了,所有线程B直接取走instance,再使用时就会出错,这就是DCL失效问题,而且这种难以跟踪和重现。
在JDK1.5之后,SUN官方注意到这种问题,调整了JVM,具体化了volatile关键字, private volatile static DclSingleton instance = null;就可以保证instance对象每次都是从主内存中读取。
DCL的有点:资源利用率高,第一次执行getInstance()时单例对象才会被初始化,效率高。缺点:
第一次加载的时候反应稍慢,也由于Java内存模型的原因偶尔会失败,在高并发的环境下有一定的缺陷,DCL是使用最多的单例模式实现方式。

枚举模式

/**
 * Created by Snail on 12/6/2017 11:04 AM
 * Contact with slowsnail0223@gmail.com
 * 枚举模式
 */
public enum EnumSingleton {

    INSTANCE;

    public void doSomething() {
    }
}

写法简单是枚举单例的最大的优点,枚举在Java中与普通的类是一样的,不仅能够有字段还能够有自己的方法,最重要的事默认枚举实例创建的单例是线程安全的,上面几种通过反序列化会重现重新穿件对象的情况,通过反序列化将一个单例的实例对象写入到磁盘,然后再堵回来,从而有效的获得一个实例。

静态内部类模式

/**
 * Created by Snail on 12/6/2017 11:10 AM
 * Contact with slowsnail0223@gmail.com
 * 静态内部类
 */
public class StaticInnerSingleton {


    private StaticInnerSingleton() {
    }

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

    private static class SingletonHolder {
        private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();
    }
}

当第一次加载StaticInnerSingleton 类时并不会初始化instance,只有第一次调用StaticInnerSingleton 的getInstance()方法才会导致instance被初始化,这种方式不仅能够确保线程安全,也能够保证单例对象的唯一性,同时也延迟了单例的实例化,是最推荐的单例实现模式。

容器单例模式

/**
 * Created by Snail on 12/6/2017 11:20 AM
 * Contact with slowsnail0223@gmail.com
 * 容器单例模式
 */
public class MapSingleton {

    private static Map<String, Object> map = new HashMap<>();

    private MapSingleton() {
    }

    public static void registerSingleton(String key, Object instance) {
        if (!map.containsKey(key)) {
            map.put(key, instance);
        }
    }

    public static Object getSingleton(String key) {
        return map.get(key);
    }
}

在程序的初始,将多种单例类型注入到一个统一的管理类中,在使用时根据key获取对象对应类型的对象,这种方式可以方便的管理多种类型的单例,并且可以使用时通过统一的接口进行获取操作,降低了用户的成本,也对用户隐藏了具体实现,降低了耦合度。

Kotlin中的单例模式

/**
 * Created by Snail on 12/15/2017 1:18 PM
 * Contact with slowsnail0223@gmail.com
 */
class KotlinSingleton {

    public var value: KotlinSingleton? = null

    private object mHolder {
        val INSTANCE = KotlinSingleton()
    }

    companion object Factory {
        fun getInstance(): KotlinSingleton {
            return mHolder.INSTANCE
        }
    }
}

不管是哪种方式实现单例模式,它们的核心原理就是将构造函数私有化,并且通过静态方法获取唯一一个实例,在这个获取的过程中必须保证线程安全,防止反序列化导致重新生成实例对象。

相关文章

  • 【设计模式】单例模式

    单例模式 常用单例模式: 懒汉单例模式: 静态内部类单例模式: Android Application 中使用单例模式:

  • Android设计模式总结

    单例模式:饿汉单例模式://饿汉单例模式 懒汉单例模式: Double CheckLock(DCL)实现单例 Bu...

  • 2018-04-08php实战设计模式

    一、单例模式 单例模式是最经典的设计模式之一,到底什么是单例?单例模式适用场景是什么?单例模式如何设计?php中单...

  • 设计模式之单例模式详解

    设计模式之单例模式详解 单例模式写法大全,也许有你不知道的写法 导航 引言 什么是单例? 单例模式作用 单例模式的...

  • Telegram开源项目之单例模式

    NotificationCenter的单例模式 NotificationCenter的单例模式分析 这种单例模式是...

  • 单例模式Java篇

    单例设计模式- 饿汉式 单例设计模式 - 懒汉式 单例设计模式 - 懒汉式 - 多线程并发 单例设计模式 - 懒汉...

  • IOS单例模式的底层原理

    单例介绍 本文源码下载地址 1.什么是单例 说到单例首先要提到单例模式,因为单例模式是单例存在的目的 单例模式是一...

  • 单例

    iOS单例模式iOS之单例模式初探iOS单例详解

  • 单例模式

    单例模式1 单例模式2

  • java的单例模式

    饿汉单例模式 懒汉单例模式

网友评论

      本文标题:单例模式

      本文链接:https://www.haomeiwen.com/subject/gjdkixtx.html