单例模式
来源:互联网 发布:淘宝怎么修改店铺类目 编辑:程序博客网 时间:2024/06/05 20:34
单例模式
主要对单例模式进行介绍,还有Java常用的单例模式实现方式:
- 单例模式特点
- 懒汉式
- 线程安全的懒汉式
- 饿汉式
- 通过枚举实现单例
- 懒汉式、饿汉式对比
单例模式特点
- 单例类在一个系统中只能有一个实例
- 系统中,其他对象使用的都是同一个实例
- 单例类必须自己创建自己的实例
懒汉式单例
懒汉式单例,因为懒汉,所以在第一次使用到实例的时候才进行实例化
/** * ProjectName:DesignPattern * PackageName:com.qzj.Singleton * Date:2017/6/7 9:39 * 懒汉式单例模式,在第一次调用的时候实例化单例对象 * * 此方法没有考虑线程安全问题,并发情况下可能会产生多个instance, * 故此,存在三种改进方法:同步锁,双检查锁定,静态内部类 */public class LazyModeSingleton { private LazyModeSingleton() { } private static LazyModeSingleton instance = null; //普通懒汉式方法 public static LazyModeSingleton getInstance() { if (instance == null) { instance = new LazyModeSingleton(); } return instance; }}
普通的懒汉式单例存在一个问题,在高并发情况下,多个线程同时执行getInstance()方法获取实例,可能会产生多个instance,故此懒汉式单例需要进行线程安全的优化。
线程安全的懒汉式
1.同步锁
为解决懒汉式的线程安全问题,主要思路就是控制同一时刻只能有一个线程来进行实例的创建,所以加锁实现同步方法成为了一种办法。
/** * ProjectName:DesignPattern * PackageName:com.qzj.Singleton * Date:2017/6/7 9:51 * <p> * 通过加上同步,处理懒汉模式的单例 */public class LazyModeSingletonSync { private LazyModeSingletonSync() { } private static LazyModeSingletonSync instance = null; //方法上加上同步 public synchronized static LazyModeSingletonSync getInstance() { if (instance == null) { instance = new LazyModeSingletonSync(); } return instance; }}
2.双检查锁
第一种方式可以解决线程同步问题,但是因为synchronized加在方法上,所以对性能影响很大,不推荐使用。双检查是先判断实例是否存在,不存在话在同步块里进行实例化,不需要进行方法的同步,这种方式保证synchronized只会在首次创建实例的时候被使用到。
/** * ProjectName:DesignPattern * PackageName:com.qzj.Singleton * Date:2017/6/7 9:56 * <p> * 双重检查锁定来优化懒汉式单例 * * 此种方式既可以实现线程实例安全的创建,又不会对性能造成大的影响 * 由于volatile关键词会屏蔽虚拟机一些代码优化,效率并不高,建议没有特别的需要不要使用 * 也就是说,虽然可以通过这种凡是实现线程安全的单例,并不建议大量采用 */public class LazyModeSingletonDoubleCheck { private LazyModeSingletonDoubleCheck() { } //“双重检查加锁”机制的实现会使用关键字volatile, // 它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。 private volatile static LazyModeSingletonDoubleCheck instance = null; public static LazyModeSingletonDoubleCheck getInstance() { //先检查实例是否存在,不存在才进入同步块 if (instance == null) { //线程安全的创建实例 synchronized (LazyModeSingletonDoubleCheck.class) { //再次检查实例是否存在 if (instance == null) { instance = new LazyModeSingletonDoubleCheck(); } } } return instance; }}
3.通过静态内部类实现
前两种方式虽然都可以解决懒汉式单例线程安全的问题,但是都对性能有一定的影响,但是通过静态内部类来实现的懒汉式就可以避免这部分性能损耗,静态内部类主要是借助虚拟机类加载保证实例的唯一和线程安全。
/** * ProjectName:DesignPattern * PackageName:com.qzj.Singleton * Date:2017/6/7 10:06 * <p> * 通过静态内部类的方式优化懒汉式单例模式 * * 此方法优于同步实现和双检查方式,即实现了线程安全,又避免了同步带来的性能问题, * * 当getInstance方法被第一次调用时,它第一次读取 SingletonHolder.instance,导致SingletonHolder类得到初始化; * 而这个类在装载并被初始化的时候,会初始化它的静 态域, * 从而创建Singleton的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。 * * 这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。 */public class LazyModeSingletonInnerClass { private LazyModeSingletonInnerClass() { } /** * 内部类,静态成员式的内部类 * 此内部类和外部类实例没有绑定关系,只有调用的时候才会初始化,从而实现了延迟加载 */ public static class SingletonHolder { /** * 静态初始化器,由JVM来保证线程安全 */ private static LazyModeSingletonInnerClass instance = new LazyModeSingletonInnerClass(); } public static LazyModeSingletonInnerClass getInstace() { return SingletonHolder.instance; }}
饿汉式单例
饿汉式单例,因为是饿汉,所以在类初始化的时候就实例化好了单例实例,也正是因此饿汉式单例本生就是线程安全的。
/** * ProjectName:DesignPattern * PackageName:com.qzj.Singleton * Date:2017/6/7 10:25 * * 饿汉模式单例:在类初始化时,已经实例化 * * 饿汉模式在类创建的时候就创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的 */public class HungryModeSingleton { private HungryModeSingleton() { } private static HungryModeSingleton instance = new HungryModeSingleton(); public static HungryModeSingleton getInstance() { return instance; }}
通过单元素枚举实现单例
为什么会通过枚举来实现单例?
参考:https://segmentfault.com/q/1010000003732558
/** * ProjectName:DesignPattern * PackageName:com.qzj.Singleton * Date:2017/6/7 15:51 * * 使用枚举来实现单例会更加简洁,而且无偿提供了序列化机制, * 并由JVM从根本上提供保障,防止多次实例化,是简洁、高效、安全的实现单例的方式 */public enum EnumModeSingleton { INSTANCE; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }}class Test { public static void main(String[] args) { EnumModeSingleton instance = EnumModeSingleton.INSTANCE; instance.setName("tom"); System.out.println("instance name is" + instance.getName()); EnumModeSingleton instance2 = EnumModeSingleton.INSTANCE; System.out.println("instance2 name is"+instance2.getName()); }}
懒汉式、饿汉式对比
1.实例化时间:饿汉式类加载的时候就开始实例化,懒汉式首次调用的时候实例化
2.线程安全:饿汉式本身线程安全,懒汉式需要特殊处理下线程安全
3.性能和占用资源:饿汉式类加载就实例化,资源会持续占用,懒汉式需要的时候才实例化占用资源,
但是响应的需要使用实例时时候,饿汉式因为已经实例化好了会快速响应,而懒汉式若此首次调会影响性能。
- 单例、单例模式
- 单例模式-多线程单例模式
- 单件模式(单例模式)
- 设计模式------单例模式
- 设计模式------单例模式
- 设计模式-单例模式
- 设计模式 - 单例模式
- 设计模式---单例模式
- 设计模式---单例模式
- PHP模式-单例模式
- 【设计模式】单例模式
- 设计模式-单例模式
- 设计模式----单例模式
- 设计模式--单例模式
- 设计模式-单例模式
- 单例模式(单子模式)
- 设计模式-单例模式
- [设计模式] 单例模式
- TCP 状态图
- window.self ,window.parent ,window.openner的使用
- Python环境布置及包安装
- spring boot 启动时候报错mongodb
- c语言结构体的位域相关知识
- 单例模式
- python:if __name__== "__main__" 的意思(作用)
- 使用git submodule添加MAVLink源文件
- linux 开机启动脚本
- 用java写一个登陆的demo
- nsq源码分析(2):nsqlookup之RegistrationDB数据库
- 微信公众号开发常用类库
- 深入浅出解析大数据平台架构
- Support Annotations注解介绍以及自定义注解代替枚举