`
sharajava
  • 浏览: 67114 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

单例到底是怎么回事

    博客分类:
  • Java
阅读更多

主要参考:http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html

及相应的转帖译文:http://blog.csdn.net/songylwq/article/details/6058771

 

单例是设计模式(时间长都有点忽略这个概念了,呵呵),也许你会说他是最“简单”的设计模式。

某种程度上是这样的,这个设计模式理解起来不困难。但是,在实现层面上,如果细研究,还是有很多值得思考和注意的地方的。

 

写个单例,很多人肯定信手拈来:

 

public class ClassicSingleton {
	private static ClassicSingleton instance = null;

	protected ClassicSingleton() {
		// Exists only to defeat instantiation.
	}

	public static ClassicSingleton getInstance() {
		if (instance == null) {
			instance = new ClassicSingleton();
		}
		return instance;
	}
}

看起来不错,还挺“聪明”,“懒”加载的模式。

但是,经验多一些的,很快就发现,有漏洞。多线程环境下可能会被两个线程分别创建出两个实例(不单例)了。

解决线程安全问题,方法也很简单,同步关键字:

 

	public static synchronized ClassicSingleton getInstance() {
		if (instance == null) {
			instance = new ClassicSingleton();
		}
		return instance;
	}

这样安全是安全了,但效率很低。线程同步的开销比普通的调用要大很多,而对于这个单例的getInstance()方法,实际上只需要在第一次调用时同步即可,唯一的单例实例创建好之后的调用,都大可不必须synchronized。  

很自然地,我们想到,不同步整个方法,同步创建对象的代码块吧:

 

	public static /*synchronized*/ ClassicSingleton getInstance() {
		if (instance == null) {
			synchronized (ClassicSingleton.class) {
				instance = new ClassicSingleton();
			}
		}
		return instance;
	}

这样行吗?很可惜,不成啊!这样的实现方式还是非线程安全的,道理跟不synchronized一样(这里不细解释了)。 

继续补救,同步块里再判断,双保险,OK吗?

 

	public static/* synchronized */ClassicSingleton getInstance() {
		if (instance == null) {
			synchronized (ClassicSingleton.class) {
				if (instance == null) {// double-check
					instance = new ClassicSingleton();
				}
			}
		}
		return instance;
	}

 

对不起,还是不行。因为Java在给变量赋值前,会先“随便” 给个值,那一“瞬间”,变量是不空(null)的。也就是说,内层的check会在特定的瞬间失效。

所以……别在同步上费劲了,没有好的结果。

 

实际上,最简单也最有效的方法只是因为我们“误会”了,所以没有使用。

 

public class Singleton {
   public final static Singleton INSTANCE = new Singleton();
   private Singleton() {
         // Exists only to defeat instantiation.
      }
}

类的静态变量天然保证了线程安全,new的操作仅在类被加载时调用一次,可以说这是由类加载机制保证的。

你可能会说,这不是“懒”加载的。其实是误会,类的静态变量只有在首次访问时才进行初始化,也就是说,这个实现本身就是“懒”加载的。

 

这里顺便提到,一个问题:单例的范围是什么?

怎么回答?我觉得应该是一个类加载器(体系)的范围。可以想象,同一个应用服务器的两个不同的Web应用中,同一个类,肯定是有其各自的单例。如果希望这种更大范围也“单例”,那就需要在类加载器做文章了。

这种场景一般没有什么需要,这里就不深入讨论了。

 

多线程环境下的单例问题解决了,还有一点特别的,就是序列化。

 

如果希望实现单例的类实现了java.io.Serializable接口,就会存在被序列化机制破坏单例的情况。在另外一篇博文中有提到:http://sharajava.iteye.com/admin/blogs/1270722

解决方案就是实现readResolve()方法:

 

class Singleton implements java.io.Serializable {
	public final static Singleton INSTANCE = new Singleton();

	private Singleton() {
		// Exists only to defeat instantiation.
	}
	
	private Object readResolve() {
		return INSTANCE;
	}
}
 

 

参考的文章中还有关于“注册”的模式实现的讨论,个人感觉很复杂但用处不大,这里就不细说了。

 

总之,一个看似简单的单例模式就包含了这么多值得思考的东西,感悟到做技术真的需要非常严谨啊!稀里糊涂,自以为是可不行哦。

 

 

 

分享到:
评论

相关推荐

    单例模式与垃圾回收机制

    ### 单例模式与垃圾回收机制 #### 一、引言 在软件开发领域,设计模式作为一种被广泛接受的最佳实践,对于提高代码质量和可维护性起着重要作用。单例模式作为23种经典设计模式之一,确保了某个类只有一个实例,并...

    单例多例模式

    "单例多例模式" 单例多例模式是软件设计中的一种重要概念,它们之间的区别和选择对系统的性能和稳定性有着重要的影响。本文将详细讲解单例多例模式的定义、产生方式、使用场景和选择标准。 一、什么是单例多例? ...

    43丨单例模式(下):如何设计实现一个集群环境下的分布式单例模式?1

    单例模式是一种设计模式,旨在确保一个类只有一个实例,并提供全局访问点。在单例模式中,类的构造函数是私有的,防止外部直接创建对象,而是通过静态方法获取该类的唯一实例。单例模式的唯一性通常是在进程范围内,...

    OC单例模式讲解

    ### OC单例模式讲解 #### 一、单例模式简介 单例模式是设计模式中的一种,属于创建型模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点。在Objective-C (简称OC)中,单例模式非常常用,尤其是在...

    单例省市级联

    在IT行业中,单例模式是一种常见的设计模式,它保证了一个类只有一个实例,并提供一个全局访问点。这样的设计在处理全局共享资源或者需要频繁创建和销毁的对象时特别有用,可以有效地节省系统资源,提高性能。本案例...

    unity中涉及的三种单例模式

    在Unity游戏开发中,单例模式是一种常用的编程设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这种模式在处理需要跨场景共享数据的情况时尤其有用,因为Unity的场景切换可能导致对象被销毁,而单例则...

    运算符单例友元重载作业

    在编程领域,运算符单例友元重载是一种高级技巧,它涉及到面向对象设计模式、类的内部工作原理以及C++中的友元函数和运算符重载。让我们深入探讨这些概念,以便更好地理解和应用。 首先,我们要理解什么是“单例...

    7种单例模式

    单例模式是软件设计模式中的一种经典模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下非常有用,比如控制共享资源、管理配置对象等。下面将详细介绍七种常见的单例模式实现...

    C++单例设计模式,单例模式

    C++单例设计模式,单例模式 C++单例设计模式,单例模式

    Android单例模式

    ### Android中的单例模式详解 #### 一、概念与特性 单例模式是软件工程中常用的设计模式之一,尤其在Java编程中非常普遍。它的核心在于确保某类在整个应用程序生命周期中仅存在一个实例,并且该类能全局访问该实例...

    java单例模式实例

    单例模式是软件设计模式中的一种经典模式,用于确保一个类只有一个实例,并提供一个全局访问点。在Java中,有多种实现单例模式的方法,每种都有其特点和适用场景。接下来,我们将深入探讨这些实现方式。 首先,我们...

    QT静态单例管理信号和槽

    QT静态单例管理信号和槽是Qt框架中一种常见的设计模式,用于确保应用程序中只有一个特定类的实例。在Qt编程中,单例模式通常用于管理全局资源,如数据库连接、配置文件读取或系统设置。这里我们将深入探讨如何在Qt中...

    细究单例那些你不知道的事(OC).zip

    单例模式是软件设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。在Objective-C(OC)编程中,单例模式被广泛应用于管理共享资源、配置信息或者提供一个全局的入口点。本篇文章将深入探讨单例...

    C#单例模式详解 C#单例模式详解C#单例模式详解

    单例模式是软件设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。在C#中,单例模式常用于管理共享资源或控制类的实例化过程,以提高性能、节约系统资源,特别是在整个应用程序生命周期内只需要一...

    Qt多工程调用单例实现,带线程锁

    在本文中,我们将深入探讨如何在Qt环境中使用多工程调用单例模式,并结合线程锁来确保数据管理的一致性和安全性。首先,我们要理解单例设计模式是一种创建型设计模式,它保证一个类只有一个实例,并提供全局访问点。...

    Java单例类

    Java单例类是一种常见的设计模式,具有三个特点:单例类只能有一个实例、单例类必须自己创建自己的唯一实例、单例类必须给所有其他对象提供这一实例。单例模式可以分为三种:懒汉子式单例、饿汉子式单例、注册式单例...

    使用单例模式实现计数器

    其中,单例模式是一种非常经典且常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。在C#中,我们可以利用单例模式来创建一个计数器类,以确保在整个应用程序的生命周期内,计数器只...

    设计模式——单例模式

    **设计模式——单例模式** 在软件工程中,设计模式是一种在特定场景下解决常见问题的标准方案,可以被复用并提升代码质量。单例模式是设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。这种模式...

    单例模式(饿汉模式、懒汉模式、DCL单例模式、枚举)

    单例模式是设计模式中的一种,它在软件工程中用于控制类的实例化过程,确保一个类只有一个实例,并提供一个全局访问点。这种模式在资源管理、缓存、日志记录等方面广泛应用。本文将详细讨论四种常见的单例实现方式:...

    Java 单例模式 工具类

    Java中的单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供全局访问点。在Java编程中,单例模式常用于控制资源的访问,比如数据库连接池、线程池或者日志对象等。本篇文章将深入探讨如何在Java中...

Global site tag (gtag.js) - Google Analytics