一、定义

单件模式(Singleton Pattern)确保一个类只有一个实例,并提供一个全局访问点。

二、适用性

1、当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

2、当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。(《设计模式:可复用面向对象软件的基础》中这句话暂不能理解)

三、类图

四、经典实现

public class Singleton {
private static Singleton uniqueInstance;
//其他有用的实例变量 //构造方法是私有的,所以在类外不能new出多个实例
private Singleton(){
//初始化其他实例变量
}
public static Singleton getInstance(){
if (uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
//其他的有用方法
}

如果不需要这个实例,它就永远不会产生,这就是“延迟实例化”(lazy instantiaze)。

五、处理多线程

在多线程下,上述经典实现中getInstance方法可能会返回不同的实例(两个线程同时判断出uniqueInstance为null,从而产生两个不同的实例)。针对这种情况,我们有以下三种方法。

1、将getInstance变成同步方法

//通过增加sychronized关键字到getInstance方法中,迫使每个线程在进入这个方法之前,要先等别的线程离开该方法。也即,不会有两个线程可以同时进入这个方法。
public static synchronized Singleton getInstance(){
if (uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}

缺点:只有第一次执行getInstance时才需要同步,之后每次调用getInstance方法,同步都是一种累赘,从而拖垮性能。

2、“急切”创建实例

public class Singleton {
//在静态初始化器(static initializer)中创建单件,保证线程安全(thread safe)
private static Singleton uniqueInstance=new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
//已经有了实例,直接使用它
return uniqueInstance;
}
}

缺点:如果这个对象非常耗费资源,而在程序的执行过程中并没有使用到它,那就造成并资源的浪费。

3、用“双重检查加锁”,在getInstance()中减少使用同步

public class Singleton {
//volatile关键词确保:当uniqueInstance变量被初始化成Singleton实例时,多个线程正确地处理uniqueInstance变量
private volatile static Singleton uniqueInstance;
private Singleton(){
}
public static Singleton getInstance(){
//检查实例,如果不存在,就进入同步区块。只有第一次才彻底执行这里的代码
if(uniqueInstance==null){
synchronized(Singleton.class){
//进入区块后,再检查一次。如果仍是null,才创建实例
if(uniqueInstance==null){
uniqueInstance=new Singleton();
}
}
}
return uniqueInstance;
}
}

缺点:版本兼容问题。在1.4及更早版本的java中,许多JVM对于volatile关键字的实现会导致双重检查加锁的失效。

六、其他

每个类加载器都定义了一个命名空间,如果有两个以上的类加载器,不同的类加载器可能会加载同一个类,从整个程序来看,同一个类会被加载多次。如果这样的事情发生在单件上,就会产生多个单件并存的怪异现象。解决方法:自行指定类加载器,并指定同一个类加载器。

单例模式会遭到破坏:

  1. 反射:调用setAccessible(true)方法,关掉安全检查,调用私有构造器。预防:修改构造器,让它在被要求创建第二个实例的时候抛出异常。
  2. 序列化和反序列化:对象序列化后再反序列化时, 会有一个新的对象被克隆出来。预防:加入readResolve()回调方法,返回指定的对象。

单件模式——Head First的更多相关文章

  1. Java设计模式——线程安全的单件模式

    单件模式,也称单例模式,用以创建独一无二的.只能有一个实例的对象. 单件模式的类图是所有模式的类图中最简单的--只有一个类.尽管从类设计的视角来看单件模式很简单,但是实现上还是会遇到一些问题,本文着重 ...

  2. C#设计模式——单件模式

    一.为何需要单件模式 需求 我们开发了一个大型的项目,其中存在许多的工具类.但是其中很多的工具类我们并不是经常使用得到,甚至 一次都不会使用.但是这些工具类都是静态的类,会消耗很多的内存,即使一次都不 ...

  3. 关于C++单件模式释放对象

    http://blog.csdn.net/windboyzsj/article/details/2790485 最近接触的一个项目要用到单件模式,我像往常一样哒哒(敲击键盘ing)一个单件模式的典型结 ...

  4. C#设计模式——单件模式(Singleton Pattern)

    一.概述在软件开发过程中,我们有时候需要保证一个类仅有一个实例,比如在一个电脑用户下只能运行一个outlook实例.这时就需要用到单件模式.二.单件模式单件模式保证一个类仅有一个实例,并提供一个访问它 ...

  5. [设计模式] javascript 之 单件模式

    单件模式说明 1. 说明:单件模式,就是静态化的访问中已经实例化的对象,这个对象只能通过一个唯一的入口访问,已经实例或待实例化的对象:面向对象语言如Java, .Net C#这样的服务端动态语言里,能 ...

  6. 【设计模式】单件模式(Singleton)--各类单件模式的比较

    单件模式 确保一个类只有一个实例,并提供一个安全的访问点. 线程安全+延时初始化+高性能(使用:延时初始化占位符模式) ------测试----------- 线程安全+[非]延时初始化 线程安全+延 ...

  7. .NET设计模式(2):单件模式(Singleton Pattern)

    转载:http://terrylee.cnblogs.com/archive/2005/12/09/293509.html 单件模式(Singleton Pattern) --.NET设计模式系列之二 ...

  8. 单件模式Singleton来控制窗体被重复或多次打开

    本文转载:http://blog.csdn.net/a0700746/article/details/4473796 一般在百度搜一下,会出来一下内容,看来很好用.Singleton很方便的一个用处就 ...

  9. NET设计模式(2):单件模式(Singleton Pattern)[转载]

    单件模式(Singleton Pattern) ——.NET设计模式系列之二 Terrylee,2005年12月07日 概述 Singleton模式要求一个类有且仅有一个实例,并且提供了一个全局的访问 ...

  10. 设计模式(二)单件模式Singleton(创建型)

    SINGLETON(单件)—对象创建型模式 几乎所有面向对象的程序中,总有一些类的对象需要是唯一的,例如,通过数据库句柄到数据库的连接是独占的.您希望在应用程序中共享数据库句柄,因为在保持连接打开或关 ...

随机推荐

  1. CentOS7 yum安装Java+Apache(httpd)+Tomcat并开启自启动

    首先,感觉yum里的东西质量不好的可以先换源. http://blog.csdn.net/qq_36731677/article/details/58288979 一.查询 两种方式可查询安装包 yu ...

  2. Socket拆包和解包

    对于基于TCP开发的通讯程序,有个很重要的问题需要解决,就是封包和拆包.下面就针对这个问题谈谈我的想法,抛砖引玉.若有不对,不妥之处,恳求大家指正.在此先谢过大家了. 一.为什么基于TCP的通讯程序需 ...

  3. RHEL6安装配置DNS服务

    RHEL6安装配置DNS服务 作者:Eric 微信:loveoracle11g 安装软件包 [root@rac1 ~]# yum -y install bind bind-chroot caching ...

  4. geoserver sld显示中文标签 style配置

    样式1: <?xml version="1.0" encoding="GB2312"?><sld:StyledLayerDescriptor ...

  5. 2-自己动手写HashMap

    public class Entry { // 键 private Object key; // 值 private Object value; //构造器 public Entry(Object k ...

  6. Java - 14 Java 日期时间

    java.util包提供了Date类来封装当前的日期和时间. Date类提供两个构造函数来实例化Date对象. 第一个构造函数使用当前日期和时间来初始化对象. Date( ) 第二个构造函数接收一个参 ...

  7. MicroMsg.SDK.WXApiImplV10: register app failed for wechat app signature check failed

    支付时: IWXAPI wxapi = WXAPIFactory.createWXAPI(this,WXAPPID,true); 替换为 IWXAPI wxapi = WXAPIFactory.cre ...

  8. linux&php:ubuntu安装php-7.2

    1.下载php源码,地址:http://www.php.net/downloads.php 这里下载的是tar.gz的包 2.解压安装 将安装包解压到/usr/local/php 安装C的编译工具 s ...

  9. day19常用模块2

    常用模块21 shelve模块  也是一种序列化方式    使用方法        1.open     sl = shelve.open("shelvetest.txt")   ...

  10. CSS 随笔

    1.动态修改div的大小 Html: <div> Hello </div> css: div { resize:both; overflow:auto; } 2. box-si ...