说说单例模式 分手后的思念是犯贱 2022-06-09 04:15 101阅读 0赞 单例模式应该都不陌生,被广泛使用的设计模式之一,在应用这个模式时,单例对象的类必须保证只有一个实例存在。 下面将会为大家介绍几种单例实现的方式,虽然实现方式有差异,但是**核心原理**都是: 1、将构造函数私有化 2、通过静态方法获取一个唯一的实例 3、在获取过程中保证线程安全 4、防止反序列化导致重新生成实例对象 ### 线程不安全的单例 ### 这种实现方式是线程不安全的,非常不推荐这种做法 public class Signleton { private static Signleton signleton; private Signleton() { } /** * 第一中方式:缺点,多线程访问时不安全 * * @return */ public static Signleton getInstance() { if (signleton == null) { signleton = new Signleton(); } return signleton; } /** * 加入该方法杜绝在反序列化时重写生成对象 * * @return * @throws ObjectStreamException */ private Object readResolve() throws ObjectStreamException { return signleton; } } ### 线程安全的单例 ### 这种方式是线程安全的,但是每次访问getInstance()方法时都会进行同步控制,效率低 public class Signleton { private static Signleton signleton; private Signleton() { } /** * 第二中方式 加上同步关键字,解决了多线程访问安全的问题 * 缺点:会降低性能,因为一旦设置好signleton变量,就不需要同步了,之后每次调用该方法会降低性能 * * @return */ public static synchronized Signleton getInstance() { if (signleton == null) { signleton = new Signleton(); } return signleton; } /** * 加入该方法杜绝在反序列化时重写生成对象 * * @return * @throws ObjectStreamException */ private Object readResolve() throws ObjectStreamException { return signleton; } } ### 双重锁的单例模式 ### 该方式避免了每次调用getInstance()方法都进行同步控制 public class Signleton { private static Signleton signleton; private Signleton() { } /** * 第三种方式, 双重检查加锁,首先检查实例是否已经创建,如果未创建才进行同步控制, * 这样只有第一次会同步,提高了性能 * 这种方式是错误的!!!!!或导致错误的结果,请看文章最后 * * @return */ //public static Signleton getInstance() { // if (signleton == null) { // synchronized (Signleton.class) { // if (signleton == null) { // signleton = new Signleton(); // } // } // } // return signleton; //} /** * 加入该方法杜绝在反序列化时重写生成对象 * * @return * @throws ObjectStreamException */ private Object readResolve() throws ObjectStreamException { return signleton; } } 但是由于signleton=new Signleton()不是原子操作,由于线程调度的原因会在某些情况下出现失效的问题,不过只需要加上volatile即可(private volatile static Signleton signleton;)。 ### 饿汉单例模式 ### 该方式会在类加载时就初始化signleton。 public class Signleton { private static Signleton signleton=new Signleton();//对应第四中方式 private Signleton() { } /** * 第四种方式,如果应用程序总是创建并使用单例实例,可以在镜头初始化器中创建单例, 使用时直接返回 * * @return */ public static Signleton getInstance() { return signleton; } /** * 加入该方法杜绝在反序列化时重写生成对象 * * @return * @throws ObjectStreamException */ private Object readResolve() throws ObjectStreamException { return signleton; } } ### 静态内部类单例模式 ### 该模式在类加载时不会初始化signleton,只有在调用get方法时才初始化 public class Signleton { /** * 第五种方式,使用静态内部类实现单例,相比饿汉模式不会在第一次加载Signleton类时就初始化sInstance, * 只有在调用getInstance时才会初始化 */ public static Signleton getInstance() { return SignletonHolder.sInstance; } private static class SignletonHolder { private static final Signleton sInstance = new Signleton(); } /** * 加入该方法杜绝在反序列化时重写生成对象 * * @return * @throws ObjectStreamException */ private Object readResolve() throws ObjectStreamException { return SignletonHolder.sInstance; } } ### 枚举单例 ### 该方式写法简单,且默认枚举实例的创建时线程安全的,并且在任何情况下它都是一个单例 public enum SingletonEnum { INSTANCE; // TODO 一些类的方法 public void doSomthing() { } } ## **第三种方式存在的问题:** ## public class DoubleCheckedLocking { // 1 private static Instance instance; // 2 public static Instance getInstance() { // 3 if (instance == null) { // 4:第一次检查 synchronized (DoubleCheckedLocking.class) { // 5:加锁 if (instance == null) // 6:第二次检查 instance = new Instance(); // 7:问题的根源出在这里 } // 8 } // 9 return instance; // 10 } // 11 } 在线程执行到第4行,代码读取到instance不为null时,instance引用的对象有可能还没有完成初始化。 instance= new Instance() 可以分解为三步 memory = allocate(); // 1:分配对象的内存空间 ctorInstance(memory); // 2:初始化对象 instance = memory; // 3:设置instance指向刚分配的内存地址 2和3在某些JIT编译器上是可以被重排序的,这样会导致这样的可能性,线程1正在执行第7步时,线程B执行了第四步instannce!=null。线程B将访问instance引用的对象,由于2,3进行了重排序,导致线程B访问到了一个未初始化的对象 可使用volatile禁止2,3的重排序(JDK1.5以后增强了volatile的语义) public class SafeDoubleCheckedLocking { private volatile static Instance instance; public static Instance getInstance() { if (instance == null) { synchronized (SafeDoubleCheckedLocking.class) { if (instance == null) instance = new Instance(); // instance为volatile,现在没问题了 } } return instance; } }
相关 单例模式 http://blog.csdn.net/zhengzhb/article/details/7331369 定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实 曾经终败给现在/ 2022年09月25日 15:30/ 0 赞/ 246 阅读
相关 单例模式 class sigle{ protected static $ins = null; public function getIns(){ 深藏阁楼爱情的钟/ 2022年07月20日 20:27/ 0 赞/ 266 阅读
相关 说说单例模式 单例模式应该都不陌生,被广泛使用的设计模式之一,在应用这个模式时,单例对象的类必须保证只有一个实例存在。 下面将会为大家介绍几种单例实现的方式,虽然实现方式有差异,但是核心原 分手后的思念是犯贱/ 2022年06月09日 04:15/ 0 赞/ 102 阅读
相关 单例模式 简介: 单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在 ﹏ヽ暗。殇╰゛Y/ 2022年05月09日 15:46/ 0 赞/ 159 阅读
相关 单例模式 <table> <tbody> <tr> <td style="vertical-align:top;width:.6868in;"> <p style 矫情吗;*/ 2021年11月22日 10:52/ 0 赞/ 298 阅读
相关 单例模式 单例模式 单例模式(SingletonPattern)是java中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及 红太狼/ 2021年11月16日 05:30/ 0 赞/ 315 阅读
相关 单例模式 应用场景 1. windows的任务管理器 2. 网站的计数器 3. 应用程序的日志 4. 数据库连接池,因为数据库连接是一种数据库资源。数据库软件系统中使用数据 r囧r小猫/ 2021年11月11日 15:08/ 0 赞/ 358 阅读
相关 单例模式 单例模式有以下特征: 1. 只有一个对象存在 2. 对象的实例化必须在类中实现 一、懒汉模式(线程不安全) package com.kevin; 谁借莪1个温暖的怀抱¢/ 2021年10月01日 07:48/ 0 赞/ 322 阅读
相关 单例模式 1.定义 单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。 2.实现步骤 1. 将该类的构造方法定义为私有方法,这样其他处 小咪咪/ 2021年09月27日 13:56/ 0 赞/ 405 阅读
相关 单例模式 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责 Dear 丶/ 2021年09月17日 02:10/ 0 赞/ 335 阅读
还没有评论,来说两句吧...