设计模式之单例模式
目的:希望对象只创建一个实例,并且提供一个全局的访问点。
使用场景: 要求只能有一个实例。比如打印机服务。多个电脑或其他设备共享一个打印机,但同一时间只能有一个输出。
还有序列生成器,整个应用必须是唯一的,只能有一个实例;windows任务管理器和回收站等。
/**
* 饿汉式单例,类加载的时候就初始化
*
*/
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return instance;
}
}
/**
* 懒汉式单例,只有第一次调用的时候才初始化
*/
public class SingletonA {
private static SingletonA instance = null;
private SingletonA(){
}
public static SingletonA getInstance(){
if(instance==null){
instance = new SingletonA();
}
return instance;
}
}
/**
* 懒汉式单例,只有第一次调用的时候才初始化。线程安全控制,采用synchronized关键字
*/
public class SingletonB {
private static SingletonB instance = null;
private SingletonB(){
}
public synchronized static SingletonB getInstance(){
if(instance==null){
instance = new SingletonB();
}
return instance;
}
}
增加了synchronized关键字后,会影响性能。多线程时大部分时间都用来synchronized关键字的准备上。所以有了double check lock(双重锁定检查)
/**
* 懒汉式单例,只有第一次调用的时候才初始化。线程安全控制,采用DCL(double check lock)
*/
public class SingletonC {
private static SingletonC instance = null;
private SingletonC(){
}
/**
* DCL(双重锁定检查),可很大程度上减轻因同步带来的性能消耗,只在instance为null的时候才同步。
*
*/
public static SingletonC getInstance(){
if(instance==null){
synchronized(SingletonC.class){
if(instance==null){
instance = new SingletonC();
}
}
}
return instance;
}
}
我们来看看这个场景:假设线程一执行到instance = new SingletonC()这句,这里看起来是一句话,但实际上它并不是一个原子操作(原子操作的意思就是这条语句要么就被执行完,要么就没有被执行过,不能出现执行了一半这种情形)。
事实上高级语言里面非原子操作有很多,我们只要看看这句话被编译后在JVM执行的对应汇编代码就发现,这句话被编译成8条汇编指令,大致做了3件事情:
1.给SingletonC的实例分配内存。
2.初始化SingletonC的构造器
3.将instance对象指向分配的内存空间(注意到这步instance就非null了)。
但是,由于Java编译器允许处理器乱序执行(out-of-order),以及JDK1.5之前JMM(Java Memory Medel)中Cache、寄存器到主内存回写顺序的规定,上面的第二点和第三点的顺序是无法保证的,也就是说,执行顺序可能是1-2-3也可能是1-3-2,
如果是后者,并且在3执行完毕、2未执行之前,被切换到线程二上,这时候instance因为已经在线程一内执行过了第三点,instance已经是非空了,
所以线程二直接拿走instance,然后使用,然后顺理成章地报错,而且这种难以跟踪难以重现的错误估计调试上一星期都未必能找得出来。
如果JDK是1.5或之后的版本,只需要将instance的定义改成“private volatile static SingletonC instance = null;”就可以保证每次都去instance都从主内存读取,就可以使用DCL的写法来完成单例模式。
还有一种实现单例的方法是采用ThreadLocal。
/**
* 采用ThreadLocal实现单例,每个线程有一个单例
*/
public class SingletonD {
private static ThreadLocal<SingletonD> singletonDHolder = new ThreadLocal<SingletonD>();
private SingletonD(){
}
public static SingletonD getInstance(){
if(singletonDHolder.get()==null){
singletonDHolder.set(new SingletonD());
}
return singletonDHolder.get();
}
}
分享到:
相关推荐
Java设计模式之单例模式的七种写法 单例模式是一种常见的设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机的驱动程序对象常...
python 设计模式之单例模式
设计模式之单例模式详解 单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。 单例模式的实现主要是...
通过研磨设计模式之单例模式的资料,你可以深入理解单例模式的原理、实现方式及其优缺点,进一步提升自己的编程技能和设计思维。学习并熟练掌握设计模式,对于成为一名优秀的Java开发者至关重要。
Java设计模式之单例模式详解 一、单例模式概览 单例模式(Singleton Pattern)是面向对象设计模式中的一种,属于创建型模式。它确保一个类仅有一个实例,并提供一个全局访问点来访问该实例。单例模式的核心在于控制...
单例模式是软件设计模式中的一种经典模式,它保证了类只有一个实例存在,并提供一个全局访问点。在Java等面向对象编程语言中,单例模式常用于管理共享资源,如数据库连接池、线程池或者配置文件等。结合工厂模式,...
### PHP设计模式之单例模式详解 #### 一、引言 在软件工程领域,设计模式是一种被广泛接受的解决方案,用于解决特定类型的问题。PHP作为一种流行的服务器端脚本语言,同样可以从这些设计模式中受益。本文将详细介绍...
JAVA设计模式之单例模式(完整版)1[定义].pdf
单例模式是一种常用的设计模式,它的核心思想是在整个应用程序中,一个类只能有一个实例存在。单例模式常用于控制资源的共享,例如数据库连接池、日志服务等。单例模式有多种实现方式,常见的包括懒汉式、饿汉式以及...
细心整合和单例模式和工厂模式的几种模型,懒汉式,饿汉式,如何并发操作模式,等都有详细讲解
设计模式之单例模式,单列模式的几种实现形式,以及其优缺点,还有就是示例,对初步了解单列模式的有所帮助
单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。 比如在某个服务器程序中,该服务器的配置信息存放...
本次我们将深入探讨两种设计模式——单例模式和装饰模式,它们在Java编程中都有着广泛的应用。 首先,让我们来理解“单例模式”。单例模式是一种创建型设计模式,其核心思想是保证一个类只有一个实例,并提供一个...
目录 单例模式的概念 单例模式的要点 单例模式类图 单例模式归类 单例模式的应用场景 单例模式解决的问题 单例模式的实现方式 单例模式实现方式对比 单例模式的概念 单例模式,顾名思义就是只有一个实例,并且由它...