Java设计模式——线程安全的单件模式
单件模式,也称单例模式,用以创建独一无二的、只能有一个实例的对象。
单件模式的类图是所有模式的类图中最简单的——只有一个类。尽管从类设计的视角来看单件模式很简单,但是实现上还是会遇到一些问题,本文着重对这一点来进行分析解决。
最简单的单件模式的实现,代码如下:
/**
* Created by McBye King on 2016/10/23.
*/
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton getSingleton(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
结合以上的代码,对单件模式进行简单的阐述。
单件模式中,利用一个静态变量来记录Singleton类的唯一实例。把构造器声明为私有的,只有自Singleton类内才可以调用构造器。为了实例化这个类,于是调用getSingleton方法,在其中实例化并返回这个实例。这里还有一个“延迟实例化”的思想,在此处,如果我们不需要这个实例,它就永远不会产生。当然在实际中可以给这个类添加其他行为。
看起来这已经是单件模式的全部了,因为单件模式太简单了,但是如果细细追究,还有很多问题。
想一个问题,如果有两个或者更多的线程调用使用上述的单例的类,会怎么样呢?
因为没有对这个单例的类对外的接口getSingleton()方法进行保护,每一个线程都可以同时调用到这个函数,有可能若干个线程同时访问到这个方法,同时进行了if(singleton == null)的判断,因为是同时的,所以大家看到的都是未曾实例化的singleton,于是紧接着就有若干个Singleton实例对象出现——这完全违反了单件模式的本意。——如果你说这也太偶然了吧,确实是的,但是确实实际存在的问题,有很大几率出现重大bug的问题
接下来我们考虑怎么解决这个问题。
1、只要把getSingleton()变成同步(synchronized)方法,多线程灾难几乎就可以解决了,如下示例:
/**
* Created by McBye King on 2016/10/23.
*/
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static synchronized Singleton getSingleton(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
通过添加synchronized关键字到getSingleton()方法中,我们迫使每个线程在进入这个方法之前,要先等候别的线程离开该方法。也就是说不允许两个线程可以同时进入这个方法。
2、添加synchronized方法无疑可以解决同步问题,但是很明显会降低性能,这又导致了另一个问题。如果可以牺牲性能,也即getSingleton()方法的性能对应用程序影响不大的时候,就用上面的方法没有错。否则,就把“延迟实例化”变成“急切”创建实例把。
/**
* Created by McBye King on 2016/10/23.
*/
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){}
public static synchronized Singleton getSingleton(){
return singleton;
}
}
在静态初始化器中创建单件,就保证了线程安全。当然了,这种办法适用于应用程序总是创建并使用单件实例,或者在创建和运行时方面的负担不会太重。
3、相对更好一点的办法是:用“双重检查加锁”,在getSingleton()中减少使用同步。
来看看代码:
/**
* Created by McBye King on 2016/10/23.
*/
public class Singleton {
private volatile static Singleton singleton;
private Singleton(){}
public static Singleton getSingleton(){
if(singleton == null){
synchronized (Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
在上述代码的getSingleton()实例化方法中,先检查实例,如果不存在,就进入同步区块;且只有第一次才会彻底执行同步区块中的代码。
其中的volatile关键字确保:当singleton变量被初始化成Singleton实例时,多个线程正确地处理singleton变量。
如果性能是考虑的重点的话,上述办法可以帮助大大减少getSingleton()的时间耗费。——前提是在Java 5以及之后的Java版本中。
4,、今天再更新一种方法,结合以上的三种方法的优点,既能拥有单件模式延迟实例化的优点,又能保证性能的要求,同时也避免了多线程情况下出错。
具体代码如下:
/**
* Created by McBye King on 2016/10/23.
*/
public class Singleton {
private static Singleton singleton;
private Singleton(){}
private static synchorized void init(){
if(singleton == null){
singleton = new Singleton();
}
}
//延迟实例化
public static Singleton getSingleton(){
if(singleton == null){
init();
}
return singleton;
}
}
如上代码所示,只有第一次实例化Singleton的时候才会调用init()方法。
5、今天再更新一种方法,使用内部类的形式,只有在第一次需要单例实例的时候才会初始化该内部类,从而实现只加载一次该实例,同时也保证线程安全。
publicclassSingleton{
// 使用内部类实现延迟加载
privatestaticclassSingletonHolder{
privatestaticSingletonsingleton=newSingleton();
}
publicstaticSingletongetSingleton() {
returnSingletonHolder.singleton;
}
}
这几天在蚂蚁金服的技术面中考察到了这种方法,很巧妙的实现了以上几种方法的优点,也避免了其缺点。
以上代码的github地址:AntiTechInterview。
原文地址:深度解析Java单例模式
Java设计模式——线程安全的单件模式的更多相关文章
- 夜话JAVA设计模式之单例模式(单件模式Singleton)
单例模式也叫单件模式,就是确保一个类只有一个实例,并提供一个全局访问点. 设计成单例即把某个类设计成我们自己管理的单独实例,避免实例对象的重复创建,我们只有通过单例类的全局访问点获取实例. 下面来看金 ...
- JAVA设计模式之单例模式(单件模式)—Singleton Pattern
1.什么是单例模式? <Head First 设计模式>中给出如下定义:确保一个类只有一个实例,并提供一个全局访问点. 关键词:唯一实例对象. 2.单例模式的实现方式: 2.1 懒汉式 对 ...
- Java设计模式(2)单态模式(Singleton模式)
定义:Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 在很多操作中,比如建立目录 数据库连接都需要这样的单线程操作. 还有,singleton能够被状态化 ...
- 重学 Java 设计模式:实战享元模式「基于Redis秒杀,提供活动与库存信息查询场景」
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 程序员的上下文是什么? 很多时候一大部分编程开发的人员都只是关注于功能的实现,只 ...
- Java设计模式之《职责链模式》及应用场景
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6530089.html 职责链模式(称责任链模式)将请求的处理对象像一条长链一般组合起来,形 ...
- Java设计模式之《享元模式》及应用场景
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6542449.html 享元模式:"享"就是分享之意,指一物被众人共享, ...
- Java设计模式之《调停者模式》及应用场景
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6518603.html 调停者模式. 我们想象一下这样的场景:一个系统内部通过许多的类互相之 ...
- JAVA设计模式之【装饰者模式】
JAVA设计模式之[装饰者模式] 装饰模式 对新房进行装修并没有改变房屋的本质,但它可以让房子变得更漂亮.更温馨.更实用. 在软件设计中,对已有对象(新房)的功能进行扩展(装修). 把通用功能封装在装 ...
- Java设计模式之《构建者模式》及应用场景
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6553374.html 构建者模式,又称建造者模式,将一部负责对象的构建分为许多小对象的构建 ...
随机推荐
- javascript高性能编程-算法和流程控制
代码整体结构是执行速度的决定因素之一. 代码量少不一定运行速度快, 代码量多也不一定运行速度慢. 性能损失与代码组织方式和具体问题解决办法直接相关. 倒序循环可以提高性能,如: ...
- 新技术≠颠覆:CIO 要有战略耐心
新技术≠颠覆:CIO 要有战略耐心 大数据,云时代,互联网思维, 物联网--最近一两年,这些字眼一次次地出现在各种大大小小的CIO会议上和他们的私下交流圈子里,作为对新技术最敏感的人群,一方面他们迫切 ...
- ORA-00821: Specified value of sga_target 3072M is too small, needs to be at least 12896M
在测试PlateSpine克隆的数据库服务器时,由于资源有限,克隆过来的数据库服务器只给了9G的内存,结果在测试时,老是会出现OOMkiller导致宕机,即out of memory killer,是 ...
- ramdisk plus v11.5安装内存虚拟硬盘
ramdisk plus v11.5.桌面版操作及应用图解说明 一.ramdisk plus程序安装方法: 1.先安装英文原版软件(RamDisk-desktop.exe桌面版),安装路径不要更改,安 ...
- Xamarin.Android多界面
一.准备 开始学习本教程前必须先完成该教程http://www.cnblogs.com/yaozhenfa/p/xamarin_android_quickstart.html 否则将无法继续. 二.界 ...
- 使用Hystrix提高系统可用性
今天稍微复杂点的互联网应用,服务端基本都是分布式的,大量的服务支撑起整个系统,服务之间也难免有大量的依赖关系,依赖都是通过网络连接起来. (图片来源:https://github.com/Netfli ...
- Unity3D新手引导开发手记
最近开始接手新手引导的开发,记录下这块相关的心得 首先客户端是Unity,在接手前,前面的同学已经初步完成了新手引导框架的搭建,这套框架比较简单,有优点也有缺点,稍后一一点评 我们的新手引导是由一个个 ...
- 面向组合子设计Coder
面向组合子 面向组合子(Combanitor-Oriented),是最近帮我打开新世界大门的一种pattern.缘起haskell,又见monad与ParseC,终于ajoo前辈的几篇文章. 自去年9 ...
- CSharpGL(12)用T4模板生成CSSL及其renderer代码
CSharpGL(12)用T4模板生成CSSL及其renderer代码 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立 ...
- ABP框架 - 时间
文档目录 本节内容: 简介 时钟 客户端 时区 客户端 绑定器与转换器 简介 虽然有些应用目标市场只是在一个时区,有些应用目标市场是许多不同时区,为满足这种需求并集中化日期操作,ABP为日期操作提供公 ...