原文链接:http://cantellow.iteye.com/blog/838473

第一种(懒汉,线程不安全):

Java代码

public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

这种写法lazy loading很明显,但是致命的是在多线程不能正常工作。

第二种(懒汉,线程安全):

Java代码

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

这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。

第三种(饿汉):

Java代码

public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}

这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例 模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到lazy loading的效果。

第四种(饿汉,变种):

Java代码

public class Singleton {private Singleton instance = null;static {instance = new Singleton();}private Singleton() {}public static Singleton getInstance() {return this.instance;}
}

表面上看起来差别挺大,其实更第三种方式差不多,都是在类初始化即实例化instance。

第五种(静态内部类):

Java代码

public class Singleton {private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}private Singleton() {}public static final Singleton getInstance() {return SingletonHolder.INSTANCE;}
}

这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第 三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使 用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化 instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能 在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。

第六种(枚举):

Java代码

public enum Singleton {INSTANCE;public void whateverMethod() {}
}

这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特 性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。

第七种(双重校验锁):
Java代码

public class Singleton {private volatile static Singleton singleton;private Singleton() {}public static Singleton getSingleton() {if (singleton == null) {synchronized (Singleton.class) {if (singleton == null) {singleton = new Singleton();}}}return singleton;}
}

这个是第二种方式的升级版,俗称双重检查锁定,详细介绍请查看:http://www.ibm.com/developerworks/cn/java/j-dcl.html
在JDK1.5之后,双重检查锁定才能够正常达到单例效果。

===========================================
总结
有两个问题需要注意:
1.如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。

2.如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。
对第一个问题修复的办法是:

Java代码

private static Class getClass(String classname) throws ClassNotFoundException {ClassLoader classLoader = Thread.currentThread().getContextClassLoader();   if(classLoader == null)   classLoader = Singleton.class.getClassLoader();   return (classLoader.loadClass(classname));   }
}

对第二个问题修复的办法是:

Java代码

public class Singleton implements java.io.Serializable {public static Singleton INSTANCE = new Singleton();protected Singleton() {}private Object readResolve() {return INSTANCE;}

对我来说,我比较喜欢第三种和第五种方式,简单易懂,而且在JVM层实现了线程安全(如果不是多个类加载器环境),一般的情况下,我会使用第三种方 式,只有在要明确实现lazy loading效果时才会使用第五种方式,另外,如果涉及到反序列化创建对象时我会试着使用枚举的方式来实现单例,不过,我一直会保证我的程序是线程安全 的,而且我永远不会使用第一种和第二种方式,如果有其他特殊的需求,我可能会使用第七种方式,毕竟,JDK1.5已经没有双重检查锁定的问题了。

superheizai同学总结的很到位:

不过一般来说,第一种不算单例,第四种和第三种就是一种,如果算的话,第五种也可以分开写了。所以说,一般单例都是五种写法。懒汉,恶汉,双重校验锁,枚举和静态内部类。
我很高兴有这样的读者,一起共勉。

转载于:https://www.cnblogs.com/longshiyVip/p/5285993.html

设计模式:单例模式7种写法相关推荐

  1. Java设计模式——单例模式的七种写法

    单例模式(Singleton) 单例模式(Singleton)是一种常用的设计模式.在Java应用中,单例模式能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处: 1.某些类创建比较频 ...

  2. java单例模式的七种写法_Java设计模式之单例模式的七种写法

    什么是单例模式? 单例模式是一种常见的设计模式,单例模式的写法有很多种,这里主要介绍三种: 懒汉式单例模式.饿汉式单例模式.登记式单例 . 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类 ...

  3. 【设计模式】各个击破单例模式的8种写法

    单例模式 在一个系统开发过程中,我们在基于节省内存资源.保证数据内容的一致性的考虑上,往往需要对某些类要求只能创建一个实例,即「保证类只有一个实例」的设计模式就是单例模式. 比如我们遇到过的各种Man ...

  4. Java设计模式之单例模式(七种写法)

    Java设计模式之单例模式(七种写法) 第一种,懒汉式,lazy初始化,线程不安全,多线程中无法工作: public class Singleton {private static Singleton ...

  5. java 静态内部类 线程安全问题_单例模式的七种写法, 面试题:线程安全的单例模式...

    http://cantellow.iteye.com/blog/838473 http://meizhi.iteye.com/blog/537563 第一种(懒汉,线程不安全): Java代码  pu ...

  6. 单例模式的八种写法比较

    转:https://www.cnblogs.com/zhaoyan001/p/6365064.html 单例模式是最常用到的设计模式之一,熟悉设计模式的朋友对单例模式都不会陌生.一般介绍单例模式的书籍 ...

  7. KandQ:单例模式的七种写法及其相关问题解析

    设计模式中的单例模式可以有7种写法,这7种写法有各自的优点和缺点: 代码示例(java)及其分析如下: 一.懒汉式 public class Singleton {private static Sin ...

  8. 使用严格模式的坏处_再见面试官:单例模式有几种写法?

    点击上方"JAVA",星标公众号重磅干货,第一时间送达 饱汉模式 饿汉模式 Holder模式 枚举模式 丑陋但好用的语法糖 总结 " "你知道茴香豆的'茴'字有 ...

  9. 单例模式:茴香豆的七种写法

    之前看一个朋友在学Java,顺口问他,你会设计模式吗? 他说知道一点吧. 然后我就问,那你会几种单例模式的写法吗? 他说,你这个孔乙己. 起篇 首先澄清一下,这篇文章并不是"茴香豆的茴字有X ...

最新文章

  1. 以下哪个不是迭代算法的缺点_海量数据分库分表方案(一)算法方案
  2. 关于 Redis 的一些新特性、使用建议和最佳实践
  3. S3 Texture Compression
  4. 浅谈数据仓库建设中的数据建模方法
  5. Flash捕神--swf seeker 下载试用版
  6. 用python画简单的图案-如何用Python画各种著名数学图案 | 附图+代码
  7. 【OpenCV】图像旋转详解,边缘用黑色填充
  8. centos samba 看不到共享目录_linux入门系列--文件共享之Samba和NFS
  9. atitit 数字音频技术概论 艾提拉著 目录 1. 声学基础 2 1.1. 1.2人耳的听觉效应9 2 2. 第1章数字音频基础 2 2.1. 1.1音频的发展历史 2 2.2. 1.2音频的发展
  10. 从零开始学游戏编程——可视化编程游戏开发工具学习指南
  11. 【系统分析师】考试内容大纲内容
  12. 怎么使用biopython_什么是Biopython? 你能用Biopython做什么? Biopython功能概。
  13. 单相无感正弦驱动方案
  14. 网络电话VOIP技术解析
  15. 给大家分享一下我的数字化转型研究资料
  16. 经纬度坐标系转东北天_经纬度坐标系转换
  17. HiveSql面试题11详解(count(1)、count(*)和count(列名)的区别)
  18. 华中科技大学计算机学院刘明,关于拟确定刘明圆等26位同志为发展对象的公示...
  19. PMBOK 第六版 识别风险:工具与技术——提示清单
  20. 华东理工大学王昊奋博士VAG小组学术报告

热门文章

  1. 农村70后、80后、90后的儿时玩具有哪些?
  2. 吃核桃仁有什么好处?
  3. 就说现在的钱有多难挣
  4. 在idea中创建mybatis-config.xml模板(在idea中创建mybatis核心配置文件模板)
  5. Maven的一些资源(配置方法、idea中toggle offline mode:切换脱机模式、idea中Toggle ‘Skip Tests’ Mode、 Dependencies 出现红色波浪线)
  6. Dubbo关于timeout等相关配置的优先级
  7. ubuntu编译libid3tag库报错问题解决
  8. ubuntu15.04在安装完vmware11后打开提示 VMware Kernel Module Updater
  9. bcp大容量复制实用工具_运行中的BCP(大容量复制程序)命令
  10. 多实例kerberos_如何使用Kerberos链接两个SQL Server实例