单例模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。

在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 !

目录

1.单例模式 2.如何使用单例模式创建类 3.何时使用Singleton 4.下载源代码

1.单例模式

有时对于某些类来说,只有一个实例很重要。 有许多对象,我们只需要它们的一个实例,而如果实例化多个对象,我们将遇到各种各样的问题,例如程序行为不正确,资源过度使用或结果不一致。

您可能只需要一个类的对象,例如,当您创建应用程序的上下文时,或者线程可管理的池,注册表设置,连接到输入或输出控制台的驱动程序等。该类型显然会导致程序不一致。

Singleton模式可确保一个类只有一个实例,并提供对其的全局访问点。 但是,尽管就类图而言,单例是最简单的,因为只有一个类,但是其实现却有些棘手。

图1

在本课程中,我们将尝试不同的方法来仅创建该类的单个对象,还将看到一种方法比另一种方法更好。

2.如何使用单例模式创建类

创建这种类型的类的方法有很多种,但仍然可以看到一种方法比另一种更好。

让我们从一个简单的方法开始。

如果提供一个使对象可访问的全局变量该怎么办? 例如:

package com.javacodegeeks.patterns.singletonpattern;public class SingletonEager {public static SingletonEager sc = new SingletonEager();}

众所周知,一个类的静态变量只有一个副本,我们可以应用它。 就目前而言,客户端代码使用此sc静态变量就可以了。 但是,如果客户端使用新的运算符,则将有此类的新实例。

要停止在类之外实例化该类,让我们将该类的构造函数设为私有。

package com.javacodegeeks.patterns.singletonpattern;public class SingletonEager {public static SingletonEager sc = new SingletonEager();private SingletonEager(){}}

这行得通吗? 我想是的。 通过使构造函数保持私有状态,其他任何类都不能实例化该类。 获取此类对象的唯一方法是使用sc静态变量,该变量确保仅存在一个对象。

但是,众所周知,直接访问类成员并不是一个好主意。 我们将提供一种方法,通过该方法,sc变量将获得访问权,而不是直接访问。

package com.javacodegeeks.patterns.singletonpattern;public class SingletonEager {private static SingletonEager sc = new SingletonEager();private SingletonEager(){}public static SingletonEager getInstance(){return sc;}
}

因此,这是我们的单例类,可确保仅创建该类的一个对象,即使存在多个请求,也将仅返回相同的实例化对象。

这种方法的一个问题是,一旦将类加载到JVM中,就会立即创建对象。 如果从未请求过该对象,则内存中将有一个无用的对象。

在需要时创建对象始终是一种好方法。 因此,我们将在第一个调用中创建一个对象,然后在其他后续调用中返回相同的对象。

package com.javacodegeeks.patterns.singletonpattern;public class SingletonLazy {private static SingletonLazy sc = null;private SingletonLazy(){}public static SingletonLazy getInstance(){if(sc==null){sc = new SingletonLazy();}return sc;}
}

getInstance()方法中,我们检查静态变量sc是否为null,然后实例化该对象并将其返回。 因此,在第一次调用时,如果sc为null,则将创建对象,而在接下来的后续调用中,它将返回相同的对象。

这看起来确实不错,不是吗? 但是,此代码将在多线程环境中失败。 想象两个线程同时访问该类,线程t1首次调用getInstance()方法,它检查静态变量sc是否为null,然后由于某种原因而被中断。 另一个线程t2调用getInstance()方法成功通过了if检查并实例化了该对象。 然后,线程t1醒来,它还创建了对象。 此时,将有两个此类。

为了避免这种情况,我们将使用synchronized关键字到getInstance()方法。 通过这种方式,我们强制每个线程等待其轮换才能进入该方法。 因此,没有两个线程会同时进入该方法。 同步带有价格,它会降低性能,但是如果对getInstance()方法的调用不会给您的应用程序造成实质性开销,则请忽略它。 另一个解决方法是转向渴望的实例化方法,如前面的示例所示。

package com.javacodegeeks.patterns.singletonpattern;public class SingletonLazyMultithreaded {private static SingletonLazyMultithreaded sc = null;private SingletonLazyMultithreaded(){}public static synchronized SingletonLazyMultithreaded getInstance(){if(sc==null){sc = new SingletonLazyMultithreaded();}return sc;}
}

但是,如果要使用同步,还有另一种称为“双重检查锁定”的技术可以减少同步的使用。 使用双重检查锁定,我们首先检查是否创建了实例,如果没有创建,则进行同步。 这样,我们只同步第一次。

package com.javacodegeeks.patterns.singletonpattern;public class SingletonLazyDoubleCheck {private volatile static SingletonLazyDoubleCheck sc = null;private SingletonLazyDoubleCheck(){}public static SingletonLazyDoubleCheck getInstance(){if(sc==null){synchronized(SingletonLazyDoubleCheck.class){if(sc==null){sc = new SingletonLazyDoubleCheck();} }}return sc;}
}

除此之外,还有其他打破单例模式的方法。

  1. 如果该类是Serializable。
  2. 如果是可克隆的。
  3. 可以通过反思来打破。
  4. 同样,如果该类由多个类加载器加载。

下面的示例说明如何保护您的类免于被多次实例化。

package com.javacodegeeks.patterns.singletonpattern;import java.io.ObjectStreamException;
import java.io.Serializable;public class Singleton implements Serializable{private static final long serialVersionUID = -1093810940935189395L;private static Singleton sc = new Singleton();private Singleton(){if(sc!=null){throw new IllegalStateException("Already created.");}}public static Singleton getInstance(){return sc;}private Object readResolve() throws ObjectStreamException{return sc;}private Object writeReplace() throws ObjectStreamException{return sc;}public Object clone() throws CloneNotSupportedException{throw new CloneNotSupportedException("Singleton, cannot be clonned");}private static Class getClass(String classname) throws ClassNotFoundException {ClassLoader classLoader = Thread.currentThread().getContextClassLoader();if(classLoader == null) classLoader = Singleton.class.getClassLoader();return (classLoader.loadClass(classname));}}
  1. 在您的单例类中实现readResolve()writeReplace()方法,并通过它们返回相同的对象。
  2. 您还应该实现clone()方法并引发异常,以使单例无法被克隆。
  3. 构造函数中的“ if条件”可以防止使用反射多次实例化单例。
  4. 为了防止从不同的类加载器实例化单例,可以实现getClass()方法。 上面的getClass()方法将类加载器与当前线程关联; 如果该类加载器为null,则该方法使用与加载单例类相同的类加载器。

尽管我们可以使用所有这些技术,但是有一种简单的方法可以创建单例类。 从JDK 1.5开始,您可以使用枚举创建单例类。 枚举常量是隐式静态的和最终的,创建后就无法更改其值。

package com.javacodegeeks.patterns.singletonpattern;public class SingletoneEnum {public enum SingleEnum{SINGLETON_ENUM;}
}

当您尝试显式实例化Enum对象时,将出现编译时错误。 当Enum静态加载时,它是线程安全的。 Enum中的clone方法是最终的,可确保枚举常量永远不会被克隆。 枚举本质上是可序列化的,序列化机制可确保不会因反序列化而创建重复的实例。 也禁止使用反射实例化。 这些确保了枚举实例不存在超出枚举常量定义的实例。

3.何时使用Singleton

  1. 一个类必须完全有一个实例,并且客户端必须可以从一个著名的访问点访问它。
  2. 当唯一的实例可以通过子类扩展,并且客户端应该能够使用扩展的实例而无需修改其代码。

4.下载源代码

这是有关Singleton Pattern的课程。 您可以在此处下载源代码: SingletonPattern-Project

翻译自: https://www.javacodegeeks.com/2015/09/singleton-design-pattern.html

单例模式示例

单例模式示例_单例设计模式示例相关推荐

  1. 反射和内省_单例设计模式–内省和最佳实践

    反射和内省 定义: Singleton是" 四人帮"设计模式的一部分,它属于创新设计模式. 在本文中,我们将更深入地研究Singleton模式的用法. 就建模而言,它是最简单的设计 ...

  2. 抽象工厂和工厂方法示例_工厂方法设计模式示例

    抽象工厂和工厂方法示例 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式如此 ...

  3. 设计模式示例_责任链设计模式示例

    设计模式示例 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式如此重要的原因 ...

  4. 透视变换–鸟瞰图_单例设计模式–鸟瞰

    透视变换–鸟瞰图 几天前,当我回到家乡时,我的一位来自同事的准青年参加了一家跨国公司的采访,在采访过程中受了重伤. 我的意思是,由于面试小组提出了一些难题,他无法使面试合格. 当我回到班加罗尔时,他分 ...

  5. 装饰着模式示例_装饰器设计模式示例

    装饰着模式示例 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式如此重要的原 ...

  6. 抽象工厂和工厂方法示例_抽象工厂设计模式示例

    抽象工厂和工厂方法示例 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式如此 ...

  7. 设计模式之单例设计模式

    1 设计模式(Design pattern) 代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用.设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案.这些解决方案是众多软件开发人 ...

  8. java实现一个单例设计模式_Java正确实现一个单例设计模式的示例

    Java正确实现一个单例设计模式的示例 发布于 2021-1-12| 复制链接 分享一篇关于关于Java正确实现一个单例设计模式的示例,小妖觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的 ...

  9. 多个if用什么设计模式_抽丝剥茧——单例设计模式

    单例设计模式 兄弟们好,今天是最后一个设计模式了,也是我们最熟悉的单例设计模式,可以说这个设计模式是我们最先接触到的设计模式了.想当年学习JavaSE的时候,老师聊到一个「饿汉式和懒汉式」,我还纠结了 ...

最新文章

  1. 在相近背景中找圆和直线
  2. kgma格式改flac_网易云,酷狗,酷我独有格式转换mp3或flac
  3. implement在JAVA中_java中的implement
  4. windows11微软拼音输入法(自带输入法)修复
  5. java导出excel设置行高列宽_Java 设置Excel自适应行高、列宽
  6. 「击败星际争霸II职业玩家」的 AlphaStar是在作弊?
  7. Mysql 第二章 数据库 DML和DQL
  8. filco的pin码_一把强行帮你退烧的键盘 plum niz atom66静电容
  9. 立创EDA的元件库导入AD
  10. js 中的 exec( )方法
  11. nvcc --version: nvcc不是内部或外部命令
  12. 基于java/php/python的毕业设计管理系统开题报告
  13. 实施金蝶ERP系统,破除信息系统壁垒
  14. Thinkepad X270 升级内存升级SSD重装WIN7经历(解决HD 620驱动 热键调节亮度)
  15. openssl加密base64编码
  16. 判断数码管是共阳极还是共阴极
  17. 项目----点餐系统
  18. ssh远程执行命令的方法
  19. python讲师招聘天津_SiKi学院Python人工智能讲师招聘
  20. 当跳蚤失去了一条腿时,就变成了聋子。

热门文章

  1. CF25E-Test【AC自动机,bfs】
  2. P4169-[Violet]天使玩偶/SJY摆棋子【CDQ分治】
  3. 51nod-猴猴吃苹果【线段树】
  4. 【动态规划】石子合并
  5. P2414 NOI2011阿狸的打字机 [AC自动机,dfs序]
  6. 6、mybatis中的sql映射文件详解(1)
  7. Hadoop入门(二十三)Mapreduce的求数量最大程序
  8. JavaFX鼠标拖拽事件
  9. art-template入门(七)之压缩页面
  10. Java IO: InputStream