设计模式之---单例模式

设计模式的世界中,单例模式可能是最简单的一种模式,虽说简单,但想要彻底的弄明白它,还是要经历一点点的波折。

下面我为大家慢慢道来:

在实际开发中,对于有些对象,我们只需要一个,比如线程池(thread pool),缓存(cache),对话框,日志对象,任务管理器等等。这些对象只能有一个实例,如果出现多个实例,则会导致许多问题的产生。

你可能会说,我们为什么不用java的全局变量,多方便的。是的,但是这样做是有缺点的,如果我们将一个对象赋值给一个全局变量,那么我们在程序一开始就必须创建好对象,一旦这个对象非常耗费资源,而程序在执行中又一直没有用到它,那么这样是非常的浪费。

单例模式,要保证一个对象只能被实例化一次,我们先来看一段雏形代码:

public class Singleton {
	private static Singleton uniqueInstance;
	private Singleton(){}

	public static Singleton getInstance(){
		if(uniqueInstance==null){
			uniqueInstance = new Singleton();
		}
		return uniqueInstance;
	}
}

在这里,我们利用一个静态变量来记录Singleton类的唯一实例,并把构造方法设置为私有,那么只有在Singleton类内部才可以调用此构造方法。然后我们用getInstance()方法实例化对象,并返回这个实例。如果uniqueInstance是空的,表示还没有创建实例,如果不为空,表示之前已经创建过对象,则直接跳过至return语句。

但是仔细想想,就会发现,上面的代码是有些问题的,问题在哪里呢?

如果我们想应用多线程,那么如果有两个或两个以上的线程要执行上面这段代码,则可能会出现产生多个实例对象的情况,也就是说,没有同步机制,可能两个线程都执行到了uniqueInstance==null的情况,那么之后就会产生两个object,而这样的结果就是不对的。

这是你可能会说,给方法加synchronized关键字啊,是的,于是有了下面的代码:

public class Singleton {
	private static Singleton uniqueInstance;
	private Singleton(){}

	public static synchronized Singleton getInstance(){
		if(uniqueInstance==null){
			uniqueInstance = new Singleton();
		}
		return uniqueInstance;
	}
}

这样,我们通过增加synchronized关键字到getInstance()方法中,可以使得每个线程在进入这个方法之前,要先等候别的线程离开该方法。也就是说不会有两个线程可以同时进入该方法。

但是这样做的问题是什么?仔细想想,很简单,那就是:同步会降低性能

也就是说,我们只有第一次执行此方法的时候才需要同步,一旦设置好了uniqueInstance变量,就不再需要同步这个方法了,因为只有第一次unqueInstance==null,之后每次调用这个方法,同步都是多余的,甚至是一种累赘。

所以,有时候要根据情况灵活的应对。

如果getInstance()的性能对应用程序不是很重要,那就什么都别做,但是必须要知道的是,同步一个方法可能会造成程序执行的效率下降100倍,所以很多时候,我们就要重新考虑了。

当然,如果我们有时很急切的需要创建实例,而不用延迟实例化的做法,就是在静态初始化器中创建单例,如下面的代码:

public class Singleton {
	private static Singleton uniqueInstance=new Singleton();
	private Singleton(){}

	public static synchronized Singleton getInstance(){
		return uniqueInstance;
	}
}

而且这段代码是线程安全的。

下面我们来看单例模式的最终版:

双重检查加锁,在getInstance()中减少使用同步:

利用双重检查加锁(double-checked locking),首先检查是否实例已经创建了,如果未创建,才进行同步,这样,只有第一次会同步,而这正是我们想要的:

public class Singleton {
	private volatile static Singleton uniqueInstance;
	private Singleton(){}

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

volatile关键字,用来确保将变量的更新操作通知到其他线程,保证新值能立即同步到主内存,以及每次使用前立即从主内存刷新。当把变量声明为volatile后,编译器与运行时都会注意到这个变量是共享的。

在这里,volatile关键字确保了,当uniqueInstance变量被初始化成Singleton实例时,多个线程能正确的处理uniqueInstance变量。

如果性能是你关系的重点,那么这个做法可以帮你大大减少getInstance()的时间耗费。

时间: 2024-08-26 08:36:19

设计模式之---单例模式的相关文章

Java设计模式:单例模式

概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,但只能

[转]JAVA设计模式之单例模式

原文地址:http://blog.csdn.net/jason0539/article/details/23297037 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话

设计模式 之 单例模式

单例模式思路: 私有化构造方法: 防止实例化 私有化克隆方法: 防止克隆 私有化静态属性: 保存对象 公有化静态方法: 获取对象 代码: <?php //设计模式:单例模式 class Singleton { //私有化静态属性:用于保存对象 private static $obj; //私有化构造方法 private function __construct(){} //公有化静态方法:用于实例化对象 public static function getObj() { //判断对象是否存在 i

设计模式实例学习-单例模式(Android中的使用场景)

1.设计模式实例-单例模式 单例模式,故名思议,是指在一个类中通过设置静态使得其仅创造一个唯一的实例.这样设置的目的是满足开发者的希望--这个类只需要被实例化创建一次,同时因为其为静态的缘故,加载的速度也应该快于正常实例化一个类的速度(理论上). 在Android开发中,当我们需要创建一个Fragment的时候常常会用到这样的模式,没有代码的学习是虚无的,接下来亮代码学习: public class SelectFrame extends Fragment { private final sta

(九)JAVA设计模式之单例模式

JAVA设计模式之单例模式 一.单例模式的介绍 Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点.     全局对象和Singleton模式有本质的区别,因为大量使用全局对象会使得程序质量降低,而且有些编程语言根本不支持全局变量.最重要的是传统的全局对象并不能阻止一个类被实例化多次. 二.单例模式的特点 单例类只能有一个实例 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例.

C#设计模式(1)——单例模式

一.引言 最近在设计模式的一些内容,主要的参考书籍是<Head First 设计模式>,同时在学习过程中也查看了很多博客园中关于设计模式的一些文章的,在这里记录下我的一些学习笔记,一是为了帮助我更深入地理解设计模式,二同时可以给一些初学设计模式的朋友一些参考.首先我介绍的是设计模式中比较简单的一个模式——单例模式(因为这里只牵涉到一个类) 二.单例模式的介绍 说到单例模式,大家第一反应应该就是——什么是单例模式?,从“单例”字面意思上理解为——一个类只有一个实例,所以单例模式也就是保证一个类只

.NET设计模式之(单例模式)

1.单例模式,一个类只能new一个对象 2.举例,资源管理器,文件管理器,地球等: 3.创建单例: (1)创建一个Earth类 class Earth { public Earth() { } } (2)将构造函数 私有化 class Earth { private Earth() { } } (3)声明一个静态私有的字段,初始化一个实例 class Earth { private static Earth instance=new Earth(); private Earth() { } }

Java 设计模式(3)单例模式

前言 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,

设计模式【单例模式】

Java中单例模式是一种常见的设计模式,单例模式分为:饿汉式单例模式.懒汉式单例模式.登记式单例模式.枚举式单例模式.作为对象的常见模式的单例模式,确保某一类只有一个实例,而且自行实例化并向整个系统提供这个实例. 单例模式的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例. 举例说明:在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实

重头开始学23种设计模式:单例模式

最近感觉做程序又开始浑浑噩噩,对设计模式和算法基本了解,但基本不会用.所以打算最近1个月把设计模式和算法重新,温故而知新下. 首先从程序开发经常涉及到的23种设计模式开始,希望这次能更加熟练的运用设计模式来加强自己的开发能力. 首先从单例模式开始: 单例模式在我的理解是对程序对象的缓存,防止不断new,保持对象唯一性,提高程序性能. namespace SinglePattern { class Program { static void Main(string[] args) { for (i