设计模式(5)--单件模式

同步一个方法可能造成程序执行效率下降100倍.

静态初始化的控制权是在Java手上

一个类,一个责任 原则. ( 类应该做一件事,而且只做一件事)  但单件做了两件事, 一是 管理自己的实例(并提供全局访问变量) 二是在应用程序中担任角色,

(1). 私有构造器.不提供对外访问   (2). 静态方法对外提供类本身实例.    (3)  . 只有一个实例

单例模式:  ( 管理共享资源 如数据库连接,或者线程池)  MVC  DAO Service 层

延迟实例化(懒汉式) 有线程安全问题  --lazy Instance

急切实例化 engerly   (饿汉式)

1. OO原则:

(1) 封装变化 (2) 多用组合,少用继承 (3) 针对接口编程,不针对实现编程 (4) 为交互对象之间的松耦合设计而努力 (5) 类应该对扩展开放,对修改关闭 (6) 依赖抽象,不要依赖具体类.

2.OO模式: 单例模式: 确保一个类只有一个实例,并提供全局访问点.

> 延迟实例化:   有着线程安全问题

public class Singleton{

private static Singleton uniqueInstance;

private Singleton(){}

public static synchronized  Singleton getInstance(){    //解决了线程问题但却降低了效率.  去掉 synchronized  会有线程安全问题

if(uniqueInstance ==null){

uniqueInstance = new Singleton();

}

return uniqueInstance;

}

}

---------------

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

利用双重检查加锁(double-checked locking) ,首先检查是否实例已经创建了,如果尚未创建,"才"进行同步.这样一来,只有第一次会同步.

public class  Singleton{

private volatile  staitc Singleton  uniqueInstance ;

private Singleton(){}

public static Singleton getInstance(){

if(uniqueInstance ==null){

synchronized(Singleton.class){   //因为是静态方法中

if(uniqueInstance ==null){

uniqueInstance = new Singleton();

}

}

}

return  uniqueInstance;

}

}

(1) volatitle 关键词确保,当uniqueInstance 变量被初始化成Singleton实例时,多个线程正确地处理uniqueInstance 变量.

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

(3) 双重检查加锁不适用于 1.4及更早的版本的Java.  在之前版本许多JVM对volatile关键字的实现会导致双重检查加锁失效.

>. 急切实例化

(1). JVM 保证在任何线程访问Instance静态变量之前,一定先创建此实例.

public  class Singleton{

private static Singleton uniqueInstance = new Singleton();    //这里可以用final修饰

private Singleton(){}

public static Singleton getInstance(){

return uniqueInstance;

}

}

(1). 当你需要控制实体个数时, 使用单例模式.

(2). 创建一个类, 把所有方法和变量定义为静态的, 把类直接当做一个单件.?   (类的单件 and  对象的单件)

如果你的类自己给自足,而且不依赖于复杂的初始化,那么你可以这么做. 但是,因为静态初始化的控制权是在Java手上.这么做有可能导致混乱.特别是当许多类牵涉其中的时候,

这么做常常会造成一些微妙的,不容易发现的和初始化的次序有关的BUG.  除非你有绝对的必要使用类的单件.否则,还是建议使用对象的单件.比较保险

(3). 类加载器(classloader)  两个类加载器可能有机会各自创建自己的单件模式.?

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

(4). 全局变量 VS  单件模式

在Java中,全局变量基本上就是对 对象的静态引用. 在这样的情况下全局变量有一个缺点,我们已经提到了其中一个:急切实例化VS延迟实例化.  但我们要记住这个模式的目的:  确保类只有一个实例并提供全局访问. 全局变量可以提供全局访问, 但是不能确保只有一个实例. 全局变量也会变相鼓励开发人员,用许多全局变量指向许多小对象来选成命名空间(namespace)的污染.
单件不鼓励这样的现象, 但单件仍然可能被滥用.

   高亮--全局变量缺点:如果将对象赋值给一个全局变量,那么你必须在程序一开始就创建好对象①,万一这个对象非常耗资源,而程序在这次的执行中又一直没用到它.

利用单件模式,我们可以需要时才创建对象.

 : 这其实和实现有关.有些JVM的实现是: 在用到的时候才创建对象.

(5) 谣传垃圾收集器会吃掉单件, 这过份夸大了!

在Java 1.2之前,, 垃圾收集器有个BUG , 会造成单件在没有全局的引用时被当作垃圾清除.也就是说,如果一个单件只有本单件类引用它本身,那么该单件,就会被当作垃圾清除.这造成让人困惑的BUG: 因为单件在被清除之后, 下次调用getInstance()会产生一个"全新的"单件. 对很多程序来说,这会造成让人困惑的行为,因为对象的实例变量值都不见了,一切回到最原始的设置(例如: 网络连接被重置).

Java 1.2以后,这个bug 已经被修正了,也不再需要一个全局引用来保护单件.

要点:

  (1). 单件模式确保程序中一个类最多只有一个实例.

(2).  单件模式也提供 访问这个实例的全局点.

(3).   在Java中实现单件模式需要私有的构造器,一个静态方法和 一个静态变量.

(4).   确定在性能和资源上的限制,然后小心地选择适当的方案来实现单件.以解决多线程的问题(我们必须认定所有的程序是多线程的).

(5) . 如果不是采用第五版的Java 2, 双重检查加锁实现会失效.

(6). 如果使用多个类加载器,可能会导致单件失效而产生多个实例

(7). 如果使用 JVM 1.2或之前的版本, 你必须建立单件注册表,以免垃圾收集器将单件回收.

(0) volatitle 关键词 :

Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。

这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。

而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。

使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。

由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。

就跟C中的一样 禁止编译器进行优化~~~~

设计模式(5)--单件模式,布布扣,bubuko.com

时间: 2024-08-02 15:09:47

设计模式(5)--单件模式的相关文章

设计模式之单件模式

一.概述 /*    一般情况下,我们建立的一些类是属于工具性质的,基本不用存储太多的跟自身有关的数据,在这种情况下,每次都去new一个对象,即增加了开销,也使得代码更加臃肿.    其实,我们只需要一个实例对象就可以.如果采用全局或者静态变量的方式,会影响封装性,难以保证别的代码不会对全局变量造成影响.    考虑到这些需要,我们将默认的构造函数声明为私有的,这样就不会被外部所new了,甚至可以将析构函数也声明为私有的,这样就只有自己能够删除自己了.    在Java和C#这样纯的面向对象的语

设计模式之单件模式(Singleton Pattern)

一.单件模式是什么? 单件模式也被称为单例模式,它的作用说白了就是为了确保“该类的实例只有一个” 单件模式经常被用来管理资源敏感的对象,比如:数据库连接对象.注册表对象.线程池对象等等,这种对象如果同时存在多个的话就会造成各种不一致的麻烦(你总不希望发生数据库重复连接的异常吧) 二.如何保证类的实例只有一个? (这个问题看似简单,但如果没有接触过单件模式的话,要自己想出来解决方案还是需要一些天赋的..不信的话,可以试着想想..) 1.类的实例可能只有一个吗?貌似只要知道类名就可以随便new了吧?

设计模式 6 —— 单件模式

设计模式目录: 设计模式 1 ——观察者模式 设计模式 2 —— 装饰者模式 设计模式 3 —— 迭代器和组合模式(迭代器) 设计模式 4 —— 迭代器和组合模式(组合) 设计模式 5 —— 工厂模式 设计模式 6 —— 单件模式 概述:

设计模式 11 —— 代理模式

设计模式目录: 设计模式 1 ——观察者模式 设计模式 2 —— 装饰者模式 设计模式 3 —— 迭代器和组合模式(迭代器) 设计模式 4 —— 迭代器和组合模式(组合) 设计模式 5 —— 工厂模式 设计模式 6 —— 单件模式 设计模式 7 —— 命令模式 设计模式 8 —— 适配器和外观模式 设计模式 9 —— 模板方法模式 设计模式 10 —— 状态模式 设计模式 11 —— 代理模式 概述 一 代理模式基本概念 二 参考 一 代理模式基本概念 代理模式为另一个对象提供一个替身或占位符以

设计模式 7 —— 命令模式

设计模式目录: 设计模式 1 ——观察者模式 设计模式 2 —— 装饰者模式 设计模式 3 —— 迭代器和组合模式(迭代器) 设计模式 4 —— 迭代器和组合模式(组合) 设计模式 5 —— 工厂模式 设计模式 6 —— 单件模式 设计模式 7 —— 命令模式 概述 第1部分 问题引入 第2部分 定义和实现 第3部分 使用宏命令 第1部分 问题引入 首先看下,下面的要求: 实现命令接口 首先,让说有的命令对象实现相同的包含一个方法的接口. 1 /** 2 * 命令接口 3 * @ClassNam

【C#设计模式】01.你真的知道线程安全的“单件模式”吗?

概述: 单件模式的类图可以说是所有模式的类图中最简单的,事实上,它的类图上只有一个类. 尽管从设计的视角来说它很简单,但是实现上还是会遇到相当多的波折. 一.职责: 1.保证一个类有且仅有一个实例 2.且提供一个全局访问点 二.代码中需要用到的地方 线程池(Thread Pool)/缓存(cache)/对话框/处理偏好设置和注册表的对象/日志对象/充当打印机/显卡等设备的驱动程序的对象. 三.生活中用到的地方 1.考勤记录仪可以有多台,但是时钟必须只有一个,所有的考勤记录必须根据这个时钟来生成打

设计模式(六):Singleton 单件模式 -- 创建型模式

1.定义 当需要控制一个类的实例数量且调用者可以从一个公共的访问点访问时. 2.适用场景 1. 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时. 2. 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时. 3.评价 优点: 1. 对唯一实例的受控访问, 因为Singleton类封装它的唯一实例,所以它可以严格的控制客户怎样以及何时访问它. 2. 缩小名空间,Singleton模式是对全局变量的一种改进.它避免了那些存储唯一实例的全局变量污染名空

设计模式 - 单件模式(singleton pattern) 详解

单件模式(singleton pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/28595349 单件模式(singleton pattern) : 确保一个类只有一个实例, 并提供一个全局访问点. 单价模式包括3个部分: 私有构造器, 静态变量, 静态方法. 具体方法: 1. 标准的单例模式: /** * @time 2014.6.5 */ package singleton; /** * @author

[设计模式]单件模式

单件模式确保一个类只有一个实例并提供一个全局访问点.实现起来也很简单,如果一个类只想有一个实例的话,那么这个类将构造函数私有化,并利用一个静态变量记录这个类的唯一实例,还要提供一个静态方法返回这个类的实例. 但是单件模式在多线程情况下可能会有些问题,解决方法一是使用同步方法返回实例,二是使用急切实例化,三是使用双重检查加锁,就是先检查实例,如果不存在就进入同步块. 类图: 参考:<Head First设计模式>