单例模式:个人认为这个是最简单的一种设计模式,而且也是在我们开发中最常用的一个设计模式。

单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。我们前面学习的很多类都是单例的。比如最典型的就是Servlet类!Servlet类被设计成单例,被所有线程共享!

Java Singleton模式为我们提供了这样实现的可能。使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection)。

单例模式也是一种比较常见的设计模式,它到底能带给我们什么好处呢?其实无非是三个方面的作用:

1、控制资源的使用,通过线程同步来控制资源的并发访问;

2、控制实例产生的数量,达到节约资源的目的。

3、作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。

缓存、日志、创建比较耗时的往往可以设计成单例

单例模式主要点

  1、私有的静态属性

  2、私有的构造方法

  3、公共的创建接口

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

  1. public class Singleton {
  2. private static Singleton instance;
  3. private Singleton (){}
  4. public static Singleton getInstance() {
  5. if (instance == null) {
  6. instance = new Singleton();
  7. }
  8. return instance;
  9. }
  10. }

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

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

  1. public class Singleton {
  2. private static Singleton instance;
  3. private Singleton (){}
  4. public static synchronized Singleton getInstance() {
  5. if (instance == null) {
  6. instance = new Singleton();
  7. }
  8. return instance;
  9. }
  10. }

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

第三种(饿汉):

  1. public class Singleton {
  2. private static Singleton instance = new Singleton();
  3. private Singleton (){}
  4. public static Singleton getInstance() {
  5. return instance;
  6. }
  7. }

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

第四种(饿汉,变种):

  1. public class Singleton {
  2. private Singleton instance = null;
  3. static {
  4. instance = new Singleton();
  5. }
  6. private Singleton (){}
  7. public static Singleton getInstance() {
  8. return this.instance;
  9. }
  10. }

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

第五种(静态内部类):

  1. public class Singleton {
  2. private static class SingletonHolder {
  3. private static final Singleton INSTANCE = new Singleton();
  4. }
  5. private Singleton (){}
  6. public static final Singleton getInstance() {
  7. return SingletonHolder.INSTANCE;
  8. }
  9. }

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

第六种(枚举):

  1. public enum Singleton {
  2. INSTANCE;
  3. public void whateverMethod() {
  4. }
  5. }

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

第七种(双重校验锁):

  1. public class Singleton {
  2. private volatile static Singleton singleton;
  3. private Singleton (){}
  4. public static Singleton getSingleton() {
  5. if (singleton == null) {
  6. synchronized (Singleton.class) {
  7. if (singleton == null) {
  8. singleton = new Singleton();
  9. }
  10. }
  11. }
  12. return singleton;
  13. }
  14. }

这个是第二种方式的升级版,俗称双重检查锁定,详细介绍请查看:http://www.ibm.com/developerworks/cn/java/j-dcl.html

在JDK1.5之后,双重检查锁定才能够正常达到单例效果。

总结

有两个问题需要注意:

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

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

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

  1. private static Class getClass(String classname)
  2. throws ClassNotFoundException {
  3. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  4. if(classLoader == null)
  5. classLoader = Singleton.class.getClassLoader();
  6. return (classLoader.loadClass(classname));
  7. }
  8. }

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

  1. public class Singleton implements java.io.Serializable {
  2. public static Singleton INSTANCE = new Singleton();
  3. protected Singleton() {
  4. }
  5. private Object readResolve() {
  6. return INSTANCE;
  7. }
  8. }

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

更多技术文章请到作者网站java168信息网》》》

java设计模式之单例模式(七种方法)的更多相关文章

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

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

  2. Java设计模式(二) 工厂方法模式

    本文介绍了工厂方法模式的概念,优缺点,实现方式,UML类图,并介绍了工厂方法(未)遵循的OOP原则 原创文章.同步自作者个人博客 http://www.jasongj.com/design_patte ...

  3. JAVA设计模式总结之23种设计模式

    上一篇总结了设计模式的六大原则<JAVA设计模式总结之六大设计原则>,这一篇,正式进入到介绍23种设计模式的归纳总结. 一.什么是设计模式                         ...

  4. 折腾Java设计模式之单例模式

    博文原址:折腾Java设计模式之单例模式 单例模式 Ensure a class has only one instance, and provide a global point of access ...

  5. Java 设计模式之单例模式(一)

    原文地址:Java 设计模式之单例模式(一) 博客地址:http://www.extlight.com 一.背景 没有太多原由,纯粹是记录和总结自己从业以来经历和学习的点点滴滴. 本篇内容为 Java ...

  6. java设计模式1——单例模式

    java设计模式1--单例模式 1.单例模式介绍 1.1.核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点 1.2.常见场景 1.3.单例模式的优点 1.4.常见的五种单例模式实现 ...

  7. java设计模式之单例模式你真的会了吗?(懒汉式篇)

    java设计模式之单例模式你真的会了吗?(懒汉式篇) 一.什么是单例模式? 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供 ...

  8. java 设计模式之单例模式

    -------Success is getting what you want, happiness is wanting what you get. java设计模式之单例模式(Singleton) ...

  9. java解析xml的三种方法

    java解析XML的三种方法 1.SAX事件解析 package com.wzh.sax; import org.xml.sax.Attributes; import org.xml.sax.SAXE ...

随机推荐

  1. 第十七章——配置SQLServer(1)——为SQLServer配置更多的处理器

    原文:第十七章--配置SQLServer(1)--为SQLServer配置更多的处理器 前言: SQLServer提供了一个系统存储过程,SP_Configure,可以帮助你管理实例级别的配置.微软建 ...

  2. topshelf和quartz

    topshelf和quartz内部分享 阅读目录: 介绍 基础用法 调试及安装 可选配置 多实例支持及相关资料 quartz.net 上月在公司内部的一次分享,现把PPT及部分交流内容整理成博客. 介 ...

  3. T-SQL问题解决集锦——数据加解密

    原文:T-SQL问题解决集锦--数据加解密 以下代码已经在SQLServer2008上的示例数据库测试通过 问题一:如何为数据进行加密与解密,避免使用者窃取机密数据? 对于一些敏感数据,如密码.卡号, ...

  4. MEF初体验之二:定义组合部件和契约

    组合部件 在MEF中,一个组合部件就是一个组合单元,组合部件"出口"其它组合部件需要的服务并且从其它部件"进口"需要的服务.在MEF编程模型中,为了声明组合部件 ...

  5. STL源代码分析 集装箱 stl_set.h

    本文senlie原版的,转载请保留此地址:http://blog.csdn.net/zhengsenlie set ------------------------------------------ ...

  6. mount命令使用具体解释(Linux)

    linux是一个优秀的开放源代码的操作系统,能够执行在大到巨型小到掌上型各类计算机系统上,随着 linux系统的日渐成熟和稳定以及它开放源代码特有的优越性,linux在全世界得到了越来越广泛的应用. ...

  7. Android使用代码消除App数据并重新启动设备

    /** * 使用代码消除App数据 * 我们不寻常的清除App数据,中找到相应的App * 然后选择其清除数据.以下给出代码实现. * * 注意事项: * 1 设备须要root * 2 该演示样例中删 ...

  8. Android:创建耐磨应用 - 定义自己的布局

    创建自己的自定义布局(Creating Custom Layouts) 本文介绍如何创建自己的自定义通知和使用可穿戴UI库来创建自己的自定义布局同时你还需要知道耐磨设计标准(Wear Design P ...

  9. fastjson经常用法

    首先,JSON究竟是什么? JSON就是一串字符串 仅仅只是元素会使用特定的符号标注. {} 双括号表示对象 [] 中括号表示数组 "" 双引號内是属性或值 : 冒号表示后者是前者 ...

  10. 基于低压电力采集平台DW710C的基础开发

    实验课题 (1)自己定义通信规约,採用java或C++编写简单的PC端上位机软件,实现採集器与PC机的通信.实验可在DW710C-PCproject下进行. (2)实现LCD显示字符.数字.汉字和简单 ...