一、定义
单例模式(Singleton pattern):确保一个类只有一个实例,并提供一个全局的访问点。
这个定义包含两层意思:
第一:我们把某个类设计成自己管理的一个单独实例,同时也要避免其他类再自行产生实例。要想取得单个实例,通
过单例类是唯一的途径。
第二:我们必需提供对这个实例的全局访问点:当你需要实例时,向类查询,它会给你返回单个实例。
注意:单例模式确保一个类只有一个实例,是指在特定系统范围内只能有一个实例。有时在某些情况下,使用
Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系
统中使用也要注意这种情况,因为EJB是跨服务器,跨JVM的。
1)某个框架容器内:如Spring IOC容器,可以通过配置保证实例在容器内的唯一性。
2)再如单一JVM中、单一类加载器加载类的情况可以保证实例的唯一性。
如果在两个类加载器或JVM中,可能他们有机会各自创建自己的单个实例,因为每个类加载器都定义了一个命名空间
,如果有两个以上的类加载器,不同的 类加载器可能会加载同一个类,从整个程序来看,同一个类会被加载多次。
如果这样的事情发生在单例上,就会产后多个Singleton并存的怪异现象。所以如果你的程序有 多个类加载,同时你
又使用了单例模式,请一定要小心。有一个解决办法是,自行给单例类指定类加载器(指定同一个类加载器)。
二、用处
有一些对象其实我们完全只需要一个即可,如:线程池(threadpool)、缓存(cache)、注册表(registry)的对象
、设备的驱动 程序的对象等等。事实上,这些类的对象只能有一个实例,如果制造出多个实例,就会导致许多问题
的产生,例如:程序的行为异常、资源的过量使用、产生不一致 的结果等等。Java Singleton模式就为我们提供了
这样实现的可能。使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回 收
(garbage collection)。我们常常看到工厂模式中类装入器(class loader)中也用Singleton模式实现的,因为被装
入的类实际也属于资源。
三、Java Singleton模式常见的几种形式
一)使用立即创建实例,而不用延迟实例化的做法
//Singleton with final field public class Singleton { public static final Singleton uniqueInstance = new Singleton(); private Singleton(){ } //...Remainder omitted }
在这种方法中,公有静态成员是一个final域(保证了总是包含相同的对象引用)。私有构造函数仅被调用一次,用
来实例化公有的静态final域 Singleton.uniqueInstace。由于缺少公有的或者受保护的构造函数,所有保证了
Singleton的全局唯一性:一旦 Singleton类被实例化之后,只有一个Singleton实例存在——不多也不少。使用此
Singleton类的程序员的任何行为都不能改变这一点。
//Singleton with static factory public class Singleton { private static Singleton uniqueInstance = new Singleton(); private Singleton(){} public static Singleton getInSingleton(){ return uniqueInstance; } //...Remainder omitted }
二)使用延迟实例化的做法(使用公有的静态工厂方法)
public class Singleton { private static Singleton uniqueInstance ; private Singleton(){ } public static Singleton getInSingleton(){ if(uniqueInstance == null){ uniqueInstance = new Singleton(); } return uniqueInstance; } //...Remainder omitted }
先利用一个静态变量uniqueInstance来记录Singleton类的唯一实例,当我们要使用它的实例时,如果它不存在,就
利用私有的构 造器产生一个Singleton类的实例并把它赋值到uniqueInstance静态变量中。而如果我们不需要使用这
个实例,它就永远不会产生。这就 是"延迟实例化(lazy instantiaze)"。但上面这段程序在多线程环境中是不能保
证单个实例的
public class Singleton { private static Singleton uniqueInstance ; private Singleton(){ } public synchronized static Singleton getInSingleton(){ if(uniqueInstance == null){ uniqueInstance = new Singleton(); } return uniqueInstance; } //...Remainder omitted }
通过给getInstance()方法增加synchronized关键字,也就是给getInstance()方法线程加锁,迫使每次只能有一 个
线程在进入这个方法,这样就可以解决上面多线程产生的灾难了。但加锁的同步方法可能造成程序执行效率大幅度下
降,如果你的程序对性能的要求很高,同时你 的getInstance()方法调用的很频繁,这时可能这种设计也不符合程
序要求了。其实这种加锁同步的方法用在这确实有一定的问题存在,因为对 Singleton类来说,只有在第一次执行
getInstance()方法时,才真正的需要对方法进行加锁同步,因为一旦第一次设置好 uniqueInstance变量后,就不
再需要同步这个方法了。之后每次调用这个方法,同步反而成了一种累赘。
public class Singleton { // volatile关键字确保当uniqueInstance变量被初始化成Singleton实例时,多个线程正确地处理 uniqueInstance变量 private volatile static Singleton uniqueInstance; private Singleton() { } public static Singleton getInSingleton() { if (uniqueInstance == null) {// 检查实例,如是不存在就进行同步代码区 synchronized (Singleton.class) {// 对其进行锁,防止两个线程同时进入同步代码区 if (uniqueInstance == null) {// 双重检查,非常重要,如果两个同时访问的线程,当第一线程访 问完同步代码区后,生成一个实例;当第二个已进入getInstance方法等待的线程进入同步代码区时,也会产生一个新的 实例 uniqueInstance = new Singleton(); } } } return uniqueInstance; } // ...Remainder omitted }
三)Sington类的序列化
为了使Singleton类变成可序列化的(serializable),仅仅实现Serializable接口是不够的。为了维护 Singleton的
单例性,你必须给Singleton类提供一个readResolve方法,否则的话,一个序列化的实例,每次反序列化的时候都会
产 生一个新的实例。Singleton 也不会例外。
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamException; import java.io.Serializable; //Singleton with final field public class Singleton implements Serializable{ private static final long serialVersionUID = 5765648836796281035L; public static final Singleton uniqueInstance = new Singleton(); private Singleton(){ } //...Remainder omitted public static void main(String[] args) throws Exception{ //序列化 ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream ("D:\\Singleton.obj")); Singleton singleton = Singleton.uniqueInstance; objectOutputStream.writeObject(singleton); objectOutputStream.close(); //反序列化 ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream ("D:\\Singleton.obj")); Singleton singleton2 = (Singleton)objectInputStream.readObject(); objectInputStream.close(); //比较是否原来的实例 System.out.println(singleton==singleton2); } }
输出结果为:false
解决方法是为Singleton类增加readResolve()方法:
//readResolve 方法维持了Singleton的单例属性 private Object readResolve() throws ObjectStreamException{ return uniqueInstance; }
再进行测试:输出结果为true
反序列化之后新创建的对象会先调用此方法,该方法返回的对象引用被返回,取代了新创建的对象。本质上,该方法
忽略了新建对象,仍然返回类初始化时创建的那个实例。
发表评论
-
eclipse-code-12-13-14
2013-09-16 02:43 564eclipse-code-12-13-14eclipse-co ... -
JDP-[代理模式]-一个例子
2012-11-21 16:47 693/* * @author junin * @da ... -
JDP-[单例模式]-思路梳理
2012-11-20 19:47 602单例模式是属于比较常 ... -
JDP02-[策略模式]-不太理解
2012-11-20 16:38 657策略模式是在给定的输入条件下,实现某个目标的计划 ... -
JDP02-[策略模式]-鸭子模型
2012-11-19 19:12 648当我们掌握了Java的语 ... -
JDP02-[策略模式]-字符串处理
2012-11-19 19:06 445程序功能:字符串处理 ... -
JDP02-[策略模式]-多种排序算法
2012-11-19 12:27 646一) 策略模式简介 策略模式的结构图如下 ... -
设计模式学习地址
2012-11-19 11:34 520http://zohan.group.iteye.com/gr ... -
JDP-01-[单例模式]-设计思路
2012-11-17 11:03 434Singleton就是只能创建一个实例对象,所以不能拥有pub ... -
JDP-01-[单例模式]-多种实现
2012-11-17 10:39 6161. 定义: 单例模式 ...
相关推荐
适用于RD-EB、RD-ET、RD-EZ、RD-EB-MX、RD-ET-MX、RD-EZ-MX、KRD-EB、KRD-ET、KRD-EZ、KRD-EB-MX、KRD-ET-MX、KRD-EZ-MX 、SRD-R100、Q3-R100、Q3-R101、Q3-R102、DP-R103、DP-R 113、DP-R123、DP-R133、DP-R143、...
然而,对于许多用户来说,找到适用于DP-301U的驱动程序可能是一项挑战。本文将详细解析DP-301U网络打印服务器驱动的相关知识,并提供安装与使用的指导。 首先,我们需要理解什么是网络打印服务器。网络打印服务器是...
在家庭或是在办公场所分享您的打印机和的打印功能,DP-302可通过网络上轻松共享多个设备,让您的办公网络成为一个整体。 强大的性能 D-Link DP-302设备配备了强大的CPU,内存和高速的USB 2.0端口,并且能够支持...
《天际航图像快速建模系统DP-Modeler2.3》是一款专为3D建模和视觉效果设计的专业软件,结合了先进的图像处理技术和高效的工作流程,旨在为用户提供便捷、精准的三维模型构建能力。DP-Modeler是天际航公司的明星产品...
【D-Link DP-302 打印服务器驱动】是一款专为D-Link公司的DP-302打印服务器设计的驱动程序。该驱动程序在IT领域中扮演着至关重要的角色,因为它允许计算机与DP-302打印服务器之间进行有效的通信,确保打印机能够正确...
《松下DP-8016P/PK 32位驱动详解及安装指南》 在信息技术领域,打印机是日常办公不可或缺的设备之一。松下DP-8016P和DP-8020P作为高效能的商务打印机,为用户提供了高质量的文档输出服务。然而,为了让这些设备正常...
qsh-030-01-x-d-a;qsh-040-01-x-d-dp-a;qte-040-04-xxx-d-a;qte-040-xx-x-d-a (1);qth-030-01-x-d-a-l;qth-030-01-xx-d-a;qth-030-01-xx-d-a封装PCB,官方下载
DP-301U是一个实用的解决方案,尤其适用于小型办公室或家庭办公环境,它通过USB接口连接打印机,支持多种类型的打印机,确保了广泛的兼容性。 描述中提到,这个驱动程序是由D-Link官方提供的,这确保了其可靠性和...
根据提供的文件信息,我们可以推断出这是一份与微软MCP认证相关的学习资料,主要针对的是DP-600考试。下面将详细解读文件中的关键信息,并基于这些信息提炼出有关MCP认证的重要知识点。 ### 标题:“DP-600微软MCP ...
标题"DP-DP-Koppler_Rel3_www.44dpdp.com_www.44dpdp.con_EC1-DEB-DPM_GSD"中提到的"DP-DP-Koppler"可能指的是一个特定的软件或系统开发项目,其中"DP"可能是项目代号或者代表“Data Processing”的缩写,而"Koppler...
**DP-301U**是一款由D-Link推出的紧凑型打印服务器,专为实现网络共享打印而设计。它通过高速USB端口连接USB打印机,使得局域网内的任何计算机都能方便地访问该打印机。 - **特点**: - 紧凑型设计,节省空间; -...
DP-504/DP-508步进驱动器是一类细分型步进驱动器,适用于各种中小型自动化设备和仪器。这些驱动器的特点包括: - 输入电压为40/80VDC,输出电流有效值为5.0A。 - 可以驱动5.0A以下各种二相混合式步进电机。 - 采用纯...
DP-ModelerV2.3是一款由武汉天际航信息科技股份有限公司研发的图像快速建模系统。该系统主要用于通过二维图像数据构建高质量的三维模型。它能够广泛应用于地理信息系统(GIS)、城市规划、文物保护等领域。 **1.2 ...
D-Link DP-302打印服务器是一款专为网络打印环境设计的设备,它能够将传统的并行或串行打印机转换为网络打印机,使多台电脑能够在同一网络环境下共享打印资源。这款设备的核心在于其配套的软件,即DP-302打印服务器...
D-Link DP-302 打印服务器固件,最新V1.03版本。也是最终版本,支持更多打印机。
而DP-means的实现可能需要额外的库,如`dpmeans`,这是一个专门为DP-means算法编写的Python包。在给定的项目"Python-DP-Means-Clustering-master"中,很可能包含了这两个算法的代码实现,包括数据预处理、模型训练和...
此外,"PC监控软件"这一标签揭示了DP-851与个人计算机之间的通信能力。这表明DP-851不仅仅是一个独立的单板计算机,它还能够与PC协同工作,实现数据的远程监控和采集。这种通信功能在当时是非常先进的技术,它不仅...
DP-100文档是Microsoft Azure认证考试中的一个重要组件,旨在考察考生的数据科学解决方案设计和实现能力。本文档涵盖了DP-100考试的部分内容,涉及到数据科学解决方案的设计、实现和部署等方面。 从题目中,我们...
DP-900 微软 Azure 数据 Fundamentals 考试复习笔记 本文档总结了 DP-900 考试的重要知识点,涵盖了数据处理、数据仓库、数据分析、数据可视化、数据存储等方面的知识点。 一、数据处理 * 规范化数据库可以减少...