单例模式 (Singleton pattern)

What is Singleton pattern?

In Wikipedia, there is an explanation:"In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object."

一、什么是单例模式?

在维基百科中,是这样解释的,“在软件工程中,单例模式指的是对类加以限制,只允许创建一个对象的设计模式”。

也就是说,在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个(当然也可以不存在)。

单例模式是一种对象创建型设计模式,在《设计模式:可复用面向对象软件的基础》一书中提到,单例模式:“保证一个类仅有一个实例,并提供一个访问它的全局访问点”。

让类自身负责保存它的唯一实例,这个类可以保证没有其他实例被创建(通过截取创建新对象的请求)。

二、我们为什么要使用单例模式?

单例模式应该是设计模式中最简单的一种设计模式,它的应用场景如下:

在工作过程中,有些对象我们只需要一个,比如线程池、缓存、硬件设备等,

如果有多个实例同时使用,可能会造成执行冲突、结果不一致等问题。

比如我们创建了多个打印程序实例,或打印机对象,但实际的打印设备只有一台,或者打印假脱机只有一个,程序执行时,就可能会造成打印结果的混乱并使程序失去可再现性。

再比如,在一个父容器中点击某个菜单项打开一个子窗口,如果不加以控制的话,每次单击菜单项都会打开一个新窗口。这不仅会浪费内存资源,在程序逻辑上也是不可以接受的。

那么我们该如何解决这个问题呢?这就要用到下面所要详细介绍的单例模式。

三、经典单例模式

1.经典单例模式的UML图如下:

2.代码实现如下:

 1 public class Singleton {
 2
 3     // 静态的instance对象,保证全局唯一性
 4     private static Singleton instance = null;
 5
 6     // 私有的构造函数,防止外部用new关键字创建实例对象
 7     private Singleton() {
 8
 9     }
10
11     // 对外的公共静态实例方法,从类级别直接可以调用此方法
12     public static Singleton getInstance() {
13
14         // 通过判断instance是否为null,决定是否创建对象
15         if (instance == null) {
16             instance = new Singleton();
17         }
18         return instance;
19     }
20 }

注意:通过Java反射机制是能够实例化构造方法为private的类的,此时基本上所有的Java单例实现失效。

(事实上我们一般不需要这样做,所以单例模式仍有其存在的意义)

四、单例模式在多线程环境下存在的问题

对于上述代码,我们可以考虑这样一种情况:

当有两个Singleton类的实例同时被创建,并运行于不同的线程中。假如A线程在执行完上述代码第15行后意外阻塞,而B线程将继续运行,执行第16行后创建instance实例,此后如果A线程重新回到就绪状态,并得到处理器资源,进入运行状态,将再次创建instance对象,此时单例模式失效。为了解决这一问题,程序员们对单例模式进行了优化。

五、单例模式的分类

1.饿汉式单例

急切创建实例,在类初始化时,便自行实例化。

 1 public class Singleton1 {
 2
 3     //已经实例化
 4     private static final Singleton1 single = new Singleton1();
 5
 6     //私有的默认构造方法
 7     private Singleton1() {
 8
 9     }
10
11     //静态工厂方法
12     public static Singleton1 getInstance() {
13         return single;
14     }
15 }

2.懒汉式单例

在第一次调用的时候再实例化。

 1 public class Singleton2 {
 2
 3     //注意,这里没有final
 4     private static Singleton2 single = null;
 5
 6     //私有的默认构造子
 7     private Singleton2() {
 8
 9     }
10
11     //静态工厂方法,用synchronized加锁
12     public synchronized static Singleton2 getInstance() {
13          if (single == null) {
14              single = new Singleton2();
15          }
16         return single;
17     }
18 }

这种方式也存在一定的问题,同样考虑特殊情况,当A线程执行到getInstance内时意外出现阻塞,此时B线程中的实例也不能够执行getInstance操作,出现阻塞。

为了解决这一问题,对此方法可以做进一步优化:双重检查加锁法。

虽然此方法同样不完美,但相对于上面一种情形,已经做到了一定的优化。

 1 public class Singleton3 {
 2
 3     // 添加关键词volatile
 4     private volatile static Singleton3 single = null;
 5
 6     //私有的默认构造器
 7     private Singleton3() {
 8
 9     }
10
11     public static Singleton3 getInstance() {
12          if (single == null) {
13              //同步锁
14             synchronized (Singleton3.class) {
15                 if (single == null) {
16                     single = new Singleton3();
17                 }
18             }
19         }
20         return single;
21     }
22 }

3.登记式单例

将类名注册,下次从里面直接获取。

 1 import java.util.HashMap;
 2 import java.util.Map;
 3
 4 public class Singleton4 {
 5     private static Map<String,Singleton4> map = new HashMap<String,Singleton4>();
 6
 7     static{
 8         Singleton4 single = new Singleton4();
 9         map.put(single.getClass().getName(), single);
10     }
11     //保护的默认构造器
12     protected Singleton4(){
13
14     }
15
16     //静态工厂方法,返还此类惟一的实例
17     public static Singleton4 getInstance(String name) {
18         if(name == null) {
19             name = Singleton3.class.getName();
20         }
21         if(map.get(name) == null) {
22             try {
23                 map.put(name, (Singleton4) Class.forName(name).newInstance());
24             } catch (InstantiationException e) {
25                 e.printStackTrace();
26             } catch (IllegalAccessException e) {
27                 e.printStackTrace();
28             } catch (ClassNotFoundException e) {
29                 e.printStackTrace();
30             }
31         }
32         return map.get(name);
33     }
34 }

参考资料:

1.极客学院hexter老师的课程—— 设计模式之单例模式

2.《设计模式:可复用面向对象软件的基础》

Erich Gamma,Richard Helm,Ralph Johnson著

3.博文:蛊惑Into—— Java单例模式详解

4.维基百科:Singleton Pattern

推荐阅读:

博文:赵学智@行胜于言——  设计模式培训之一:为什么要用单例模式?

博文:都市耕牛—— 登记式单例实现单例模式的继承(限定一个抽象类的所有子类都必须是单例)

时间: 2024-12-08 02:28:31

单例模式 (Singleton pattern)的相关文章

二十四种设计模式:单例模式(Singleton Pattern)

单例模式(Singleton Pattern) 介绍保证一个类仅有一个实例,并提供一个访问它的全局访问点. 示例保证一个类仅有一个实例. Singleton using System; using System.Collections.Generic; using System.Text; namespace Pattern.Singleton { /// <summary> /// 泛型实现单例模式 /// </summary> /// <typeparam name=&q

ninject学习笔记二:单例模式singleton pattern

今天准备学习singleton pattern,顾单词思含义,就是一个实例的意思.单例的实现思路是:私有化构造函数,提供公有方法获取类的实例.下面定义一个音乐播放器类MusicPlayer,观察单例的实现方法 class MusicPlayer { private static readonly MusicPlayer player = new MusicPlayer(); private MusicPlayer() { } public static MusicPlayer GetInstan

设计模式之单例模式Singleton pattern

单例模式Singleton pattern 一种软件设计模式.在核心结构中只包含一个被称为单例的特殊类. 一个类只有一个对象实例,并且自行实例化向整个系统提供. 动机 一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务:一个系统只能有一个窗口管理器或文件系统:一个系统只能有一个计时工具或ID(序号)生成器.如在Windows中就只能打开一个任务管理器.如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源:如果这些窗口显示的内容不

.NET设计模式实例之单例模式( Singleton Pattern)

一.单例模式简介(Brief Introduction) 单例模式(Singleton Pattern),保证一个类只有一个实例,并提供一个访问它的全局访问点.单例模式因为Singleton封装它的唯一实例,它就可以严格地控制客户怎样访问它以及何时访问它. 二.解决的问题(What To Solve) 当一个类只允许创建一个实例时,可以考虑使用单例模式. 三.单例模式分析(Analysis)1.单例模式结构 Singleton类,定义一个私有变量instance;私有构造方法Singleton(

Swift 实现单例模式Singleton pattern的三种方法

转自:点击打开链接 From my short experience with Swift there are three approaches to implement the Singleton pattern that support lazy initialization and thread safety. These approaches might change or become redundant as the language matures. Global constant

设计模式之五:单例模式(Singleton Pattern)

单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 单例模式有三个要点: 点某个类只能有一个实例: 它必须自行创建这个实例 它必须自行向整个系统提供这个实例. 一些资源管理器常常设计成单例模式. C#中的单例模式 保证一个类仅有一个实例,并提供一个访问它的全局访问点 实现要点: 单例模式是限制而不是改进类的创建. 单例模式一般不要支持Icloneable接口,因为这可能导致多个对象实例,与单例模式的初衷违背. 单例模式一般

&quot;围观&quot;设计模式(7)--创建型之单例模式(Singleton Pattern)

单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对象的类必须保证只有一个实例存在.许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为.比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息.这种方式简化了在复杂环境下的配置管理.----维基百科(WIKIPEDIA) 个人的理解: 单例模式概念比较简单,他的目的就是只允许出现一个该类的实例,经常在JD

[设计模式]&lt;3&gt;. C++与单例模式(singleton pattern)

默默地EEer 原文地址: http://www.cnblogs.com/hebaichuanyeah/p/5608209.html 单例模式是指,保证一个类,只有唯一一个实例,并提供这个实例的全局访问. 1.不靠谱之单例模式 很容易写出如下代码,通过Singleton类中的static函数去获取唯一的static指针变量,同时把Singalton类的构造函数设置为private,不允许构造多个对象. #include "iostream" using namespace std; c

C# 单例模式(Singleton Pattern)

(新手写博客,主要是对自己学习的归纳总结.会对很多小细节详解.) 单例模式的定义: 确保一个类只有一个实例,并提供一个全局访问点. 首先实例大家应该都明白就是类生成对象的过程简单的就是String s=new String(),则s就是个实例. Q:如何只生成一个实例? A:1)首先必须将构造函数变为私有从而防止其他类实例化,并且只能有一个构造函数.因为系统会默认一个无参构造函数,而且默认public访问修饰符. 所以必须写一个私有无参让默认无效.(通常单例模式都是不带形参的) 2)在该类中声明