原文地址:http://blog.csdn.net/jason0539/article/details/23297037

概念:
  java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。
  单例模式有一下特点:
  1、单例类只能有一个实例。
  2、单例类必须自己自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。
  单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。

首先看一个经典的单例实现。

  1. public class Singleton {
  2. private static Singleton uniqueInstance = null;
  3. private Singleton() {
  4. // Exists only to defeat instantiation.
  5. }
  6. public static Singleton getInstance() {
  7. if (uniqueInstance == null) {
  8. uniqueInstance = new Singleton();
  9. }
  10. return uniqueInstance;
  11. }
  12. // Other methods...
  13. }

Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)

但是以上实现没有考虑线程安全问题。所谓线程安全是指:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。显然以上实现并不满足线程安全的要求,在并发环境下很可能出现多个Singleton实例。

  1. package jason.single;
  2. public class TestStream {
  3. String name = null;
  4. public String getName() {
  5. return name;
  6. }
  7. public void setName(String name) {
  8. this.name = name;
  9. }
  10. private TestStream() {
  11. }
  12. private static TestStream ts1 = null;
  13. public static TestStream getTest() {
  14. if (ts1 == null) {
  15. ts1 = new TestStream();
  16. }
  17. return ts1;
  18. }
  19. public void printInfo() {
  20. System.out.println("the name is " + name);
  21. }
  22. }
  1. package jason.single;
  2. public class TMain {
  3. public static void main(String[] args){
  4. TestStream ts1 = TestStream.getTest();
  5. ts1.setName("jason");
  6. TestStream ts2 = TestStream.getTest();
  7. ts2.setName("0539");
  8. ts1.printInfo();
  9. ts2.printInfo();
  10. if(ts1 == ts2){
  11. System.out.println("创建的是同一个实例");
  12. }else{
  13. System.out.println("创建的不是同一个实例");
  14. }
  15. }
  16. }

运行结果:

结论:由结果可以得知单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都会同享一个实例对象。

1.饿汉式单例类

  1. //饿汉式单例类.在类初始化时,已经自行实例化
  2. public class Singleton1 {
  3. //私有的默认构造子
  4. private Singleton1() {}
  5. //已经自行实例化
  6. private static final Singleton1 single = new Singleton1();
  7. //静态工厂方法
  8. public static Singleton1 getInstance() {
  9. return single;
  10. }
  11. }

2.懒汉式单例类

  1. //懒汉式单例类.在第一次调用的时候实例化
  2. public class Singleton2 {
  3. //私有的默认构造子
  4. private Singleton2() {}
  5. //注意,这里没有final
  6. private static Singleton2 single=null;
  7. //静态工厂方法
  8. public synchronized  static Singleton2 getInstance() {
  9. if (single == null) {
  10. single = new Singleton2();
  11. }
  12. return single;
  13. }
  14. }
  1. import java.util.HashMap;
  2. import java.util.Map;
  3. //登记式单例类.
  4. //类似Spring里面的方法,将类名注册,下次从里面直接获取。
  5. public class Singleton3 {
  6. private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();
  7. static{
  8. Singleton3 single = new Singleton3();
  9. map.put(single.getClass().getName(), single);
  10. }
  11. //保护的默认构造子
  12. protected Singleton3(){}
  13. //静态工厂方法,返还此类惟一的实例
  14. public static Singleton3 getInstance(String name) {
  15. if(name == null) {
  16. name = Singleton3.class.getName();
  17. System.out.println("name == null"+"--->name="+name);
  18. }
  19. if(map.get(name) == null) {
  20. try {
  21. map.put(name, (Singleton3) Class.forName(name).newInstance());
  22. } catch (InstantiationException e) {
  23. e.printStackTrace();
  24. } catch (IllegalAccessException e) {
  25. e.printStackTrace();
  26. } catch (ClassNotFoundException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. return map.get(name);
  31. }
  32. //一个示意性的商业方法
  33. public String about() {
  34. return "Hello, I am RegSingleton.";
  35. }
  36. public static void main(String[] args) {
  37. Singleton3 single3 = Singleton3.getInstance(null);
  38. System.out.println(single3.about());
  39. }
  40. }

《JAVA与模式》之单例模式(转载)的更多相关文章

  1. Java 序列化 序列化与单例模式 [ 转载 ]

    Java 序列化 序列化与单例模式 [ 转载 ] @author Hollis 本文将通过实例+阅读Java源码的方式介绍序列化是如何破坏单例模式的,以及如何避免序列化对单例的破坏. 单例模式,是设计 ...

  2. Java ------ 工厂模式、单例模式

    工厂模式 简单工厂模式: 1.创建Car接口 public interface Car { public void drive(); } 2.创建两个实体类,分别实现Car接口 public clas ...

  3. 《JAVA与模式》之单例模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述单例模式的: 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 单例模式的 ...

  4. Java中的GOF23(23中设计模式)--------- 单例模式(Singleton)

    Java中的GOF23(23中设计模式)--------- 单例模式(Singleton) 在Java这这门语言里面,它的优点在于它本身的可移植性上面,而要做到可移植的话,本身就需要一个中介作为翻译工 ...

  5. 《JAVA与模式》之单例模式 [转]

    在阎宏博士的<JAVA与模式>一书中开头是这样描述单例模式的: 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 单例模式的 ...

  6. Java设计模式(4)——创建型模式之单例模式(Singleton)

    一.概述 弥补一下之前没有给设计模式下的定义,先介绍一下设计模式(引用自百度百科): 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结. 使用设计 ...

  7. 《JAVA与模式》之观察者模式(转载)

    <JAVA与模式>之观察者模式(转载)  原文链接:http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html ...

  8. 资源池模式和单例模式实现的自定义数据库连接池java实现版

    在企业级开发中,我们往往不会直接使用原生的JDBC操作来实现与数据库得连接.因为数据库的连接是一个很宝贵的资源且耗时,我们往往会在内存中引入一个资源池来统一管理数据库的连接.这个模式也被总结为一种设计 ...

  9. java future模式 所线程实现异步调用(转载

    java future模式 所线程实现异步调用(转载) 在多线程交互的中2,经常有一个线程需要得到另个一线程的计算结果,我们常用的是Future异步模式来加以解决.Future顾名思意,有点像期货市场 ...

  10. 《JAVA与模式》之责任链模式 【转载】

    转载自java_my_life的博客 原文地址:http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html 在阎宏博士的&l ...

随机推荐

  1. pycharm+python+Django之web开发环境的搭建(windows)

    转载:https://blog.csdn.net/yjx2323999451/article/details/53200243/ pycharm+python+Django之web开发环境的搭建(wi ...

  2. 一步一步教你搭建和使用FitNesse

    啄木鸟之家大吕 敏捷测试已成为现在式,尽早和持续的反馈成为各研发团队的必选项.测试同学也需要跟上这个趋势.除了“找bug”.“分析需求”.“功能测试”,还需考虑“交付质量.一次做对.在没有用户界面情况 ...

  3. Discuz常见小问题-如何取消登陆发帖验证码

    1 正常情况下,用户点击登录之后,需要填写验证码 2 进入后台,点击防灌水,验证设置,然后下面的各个选项可以设置是否启用验证码.

  4. Windows版Mycat结合mysql安装配置+水平切分(转载)

    来源:https://segmentfault.com/a/1190000009495748 参考文档:Mycat安装与使用 环境 环境 版本 windows 10 java 1.8.0 mysql ...

  5. 解决工作中遇到的一个"打开,保存"文件框的bug的过程

    工作中遇到的这个问题还是很有意思的.其中嵌套了很多奇葩性的问题. (转载请指明出于breaksoftware的csdn博客) 我们来看下故事的发生过程,QA同学发现我们存在如下的bug 看到如此多的串 ...

  6. C++ 第四课:ASCII 码表

    下面的 ASCII 码表包含数值在0-127之间的字符的十进制.八进制以及十六进制表示. 十进制 八进制 十六进制 字符 描述 0 0 00 NUL   1 1 01 SOH start of hea ...

  7. WEB打印控件Lodop使用体会

                    控件的使用方法,作者都已经有详细的使用说明供使用者参考. 但是对于打印表格,确实出现一点小问题,如果表格是自然高度,也就是只设置了table的高度,此时是可以正常显示的 ...

  8. python 大小端数据转换

    "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000".decode('hex')[::-1].enc ...

  9. Java并发容器——ConcurrentSkipListMap和ConcurrentHashMap

    一:ConcurrentSkipListMap TreeMap使用红黑树按照key的顺序(自然顺序.自定义顺序)来使得键值对有序存储,但是只能在单线程下安全使用:多线程下想要使键值对按照key的顺序来 ...

  10. 〖Linux〗Kubuntu14.04 平滑字体的设置

    有没有感觉终端的字体锯齿感觉非常强? 经过搜索后发现可以平滑字体显示得更漂亮一点: System Settings > Application Appearance > Fonts I e ...