Java中的单例模式(Singleton Pattern in Java)
Introduction
单例模式在很多的框架中被广泛使用。
对于系统中的某个类来说,只有一个实例是很重要的,比如只能有一个timer和ID Producer。又比如在服务器程序中,配置信息保留在一个文件中,这些配置信息只由一个单例对象统一获取,进程中的其他对象通过这个单例对象获取这些配置信息,通过这种方式大大简化复杂环境下的配置管理。
这个时候一个类里面就只能有一个实例,并且这个实例要易于访问。我当然可以只定义一个全局变量从而保证对象随时都能访问。但是如果是这种方式来实现单例模式的话,依然可以实例化多个instance,而且被不同的对象所持有(这就违反了单例模式的条件了)不是很妙。
实现单例模式的思路是:
一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。
如果类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
Definition
Singleton Pattern:单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
- 单例类只能由一个实例
- 自行创建实例
- 自行向整个系统(所有其他对象)提供此实例
Attention
在多线程的应用场合中使用单例模式的时候要注意。如果唯一的单例尚未被创建(懒汉模式),有两个线程同时调用构建的方法,他俩都不会检测到唯一实例,于是每个线程都创建了一个实例,这就违反了单例模式中实例唯一的原则。
所以我们可以为指示类是否实例化的变量提供一个互斥锁。(会降低效率)
Java实现
常用的构建方式
- 懒汉模式。指全局的单例模式在第一次使用时被创建。
- 饿汉方式。指全局的单例模式在类装载的时候被创建。
Example
- 饿汉模式
public class Sington{
private static Singleton instance = new Singleton();
private Singleton (){
}
public static Singleton getInstance() {
return instance;
}
}
在类加载的时候完成初始化,所以类的加载速度会比较慢,但是可以很快的获取对象,优势在于不需要去考虑多线程的同步问题。
懒汉模式
2.1 lock
public class Singleton {
private static Singleton instance; private Singleton() {
} public synchronized Singleton getInstance() {
if (null == instance) {
instance = new Singleton();
}
return instance;
}
}
这样来加锁是一个比较简单粗暴的方式,但是比较无脑synchronized,每次调用getInstance都会进行一次同步,会有一定的性能消耗,实际上我只需要第一次初始化的时候加锁就好了。
2.2 double checked locking
public class Singleton {
private static volatile Singleton instance = null;
// Private constructor suppresses
// default public constructor
private Singleton() {};
//Thread safe and performance promote
public static Singleton getInstance() {
if(instance == null){
synchronized(Singleton.class){
// When more than two threads run into the first null check same time,
// to avoid instanced more than one time, it needs to be checked again.
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
双重检查锁的优势在于它先判断了对象是否已经初始化,再决定要不要加锁。
使用了volatile关键字之后,所有的写操作发生在读操作之前。这个解决方案需要 JDK5 或更高版本(因为从 JDK5 开始使用新的 JSR-133 内存模型规范,这个规范增强了 volatile 的语义)
- Initialization On Demand Holder idiom
JVM 在类的初始化阶段(即在 Class 被加载后,且被线程使用之前),会执行类的初始化。在执行类的初始化期间,JVM 会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化。
public class Singleton {
public class InstanceFactory {
private static class InstanceHolder {
public static Instance instance = new Instance();
}
public static Instance getInstance() {
return InstanceHolder.instance ; // 这里将导致 InstanceHolder 类被初始化 (只有第一次调用getInstance方法的时候,虚拟机加载InstanceHolder并且初始化instance)
}
}
}
不是很清楚这种基于类初始化的方案和上面的双重检查模式到底谁的性能更好。
但基于 volatile 的双重检查锁定的方案有一个额外的优势:除了可以对静态字段实现延迟初始化外,还可以对实例字段实现延迟初始化。
参考
Java中的单例模式(Singleton Pattern in Java)的更多相关文章
- Java 设计模式(三)-单例模式(Singleton Pattern)
1 概念定义 1.1 定义 确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 1.2 类型 创建类模式 1.3 难点 1)多个虚拟机 当系统中的单例类被拷贝运行在多 ...
- Java 基础:单例模式 Singleton Pattern
1.简介 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创 ...
- 设计模式之单例模式(Singleton Pattern)
单例模式 单例模式(Singleton Pattern)在java中算是最常用的设计模式之一,主要用于控制控制类实例的数量,防止外部实例化或者修改.单例模式在某些场景下可以提高系统运行效率.实现中的主 ...
- Java设计模式之单例模式 - Singleton
用来创建独一无二的,是能有一个实例的对象的入场券.告诉你一个好消息,单例模式的类图可以说是所有模式的类图中最简单的,事实上,它的类图上只有一个类!但是,可不要兴奋过头,尽管从类设计的视角来说很简单,但 ...
- java中的单例模式与静态类
单例模式与静态类(一个类,所有方法为静态方法)是另一个非常有趣的问题,在<Java中有关单例模式的面试问题>博文中露掉了,由于单例模式和静态类都具有良好的访问性,它们之间有许多相似之处,例 ...
- 浅谈设计模式--单例模式(Singleton Pattern)
题外话:好久没写blog,做知识归纳整理了.本来设计模式就是个坑,各种文章也写烂了.不过,不是自己写的东西,缺少点知识的存在感.目前还没做到光看即能记住,得写.所以准备跳入设计模式这个大坑. 开篇先贡 ...
- 抽象工厂(Abstract Factory),工厂方法(Factory Method),单例模式(Singleton Pattern)
在谈工厂之前,先阐述一个观点:那就是在实际程序设计中,为了设计灵活的多态代码,代码中尽量不使用new去实例化一个对象,那么不使用new去实例化对象,剩下可用的方法就可以选择使用工厂方法,原型复制等去实 ...
- 设计模式系列之单例模式(Singleton Pattern)——确保对象的唯一性
模式概述 模式定义 模式结构图 饿汉式单例与懒汉式单例 饿汉式单例 懒汉式单例 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 主要优点 适用场景 说明:设计模式系列文章是读刘伟所著 ...
- 【设计模式】单例模式 Singleton Pattern
通常我们在写程序的时候会碰到一个类只允许在整个系统中只存在一个实例(Instance) 的情况, 比如说我们想做一计数器,统计某些接口调用的次数,通常我们的数据库连接也是只期望有一个实例.Windo ...
- java中myeclipse连接mysql问题(java.lang.ClassNotFoundException: com.mysql.jdbc.Driver)
java中myeclipse连接mysql问题(java.lang.ClassNotFoundException: com.mysql.jdbc.Driver) 1.往项目中添加mysql-conne ...
随机推荐
- sklearn文本特征提取——TfidfVectorizer
什么是TF-IDF IF-IDF(term frequency-inverse document frequency)词频-逆向文件频率.在处理文本时,如何将文字转化为模型可以处理的向量呢?IF-ID ...
- autotools工具使用 good
学习GNU/LINUX开发的编程人员,上手之后不久就会在编译开源软件的时候碰到configure脚本,过段时间还会知道configure脚本是 autoconf生成的:但是真正想用起来autoconf ...
- WebBrowser中获得脚本中的变量值
//项目中添加Micrsoft.mshtml引用 --c:/temp/temp.htm-- <html> <script language="JavaScript" ...
- Oracle 裁掉北京研发团队,相应职位撤回美国(收购了NetSuite,LogFire,Dyn)
根据中国日报报道,2017年1月14日上午9点09分,甲骨文北京研发团队的同事收到了来自BU老大的一封邮件.邮件上提及,由于市场变化,甲骨文开始整合各研发中心资源公司在云计算方向发力,文末单独提出了甲 ...
- How Qt Signals and Slots Work(感觉是通过Meta根据名字来调用)
Qt is well known for its signals and slots mechanism. But how does it work? In this blog post, we wi ...
- ABP开发框架前后端开发系列---(4)Web API调用类的封装和使用
在前面随笔介绍ABP应用框架的项目组织情况,以及项目中领域层各个类代码组织,以及简化了ABP框架的各个层的内容,使得我们项目结构更加清晰.上篇随笔已经介绍了字典模块中应用服务层接口的实现情况,并且通过 ...
- Django 的路由系统
Django 的路由系统 Django 的路由系统 路由层 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$',views.ho ...
- SQL Server 2012设置某用户对某些表的记录限制其删除操作
第一步:用sa用户进入SSMS: 第二步:在安全性---用户上面点击右键---"属性": 第三步:在选择页中选择”安全对象“,点击”搜索“,弹出添加对象页面,这里默认为特定对象不用 ...
- Confluence安装、汉化及jira整合
今天上午装了一下Confluence,刚开始装的时候成功了,成功后进入数据库配置阶段,本人想把jira和confluence整合一起用,刚开始提示数据库连接问题,后来一直问题提示Connection ...
- web页面加载速度缓慢,如何优化?
参考博客: https://www.cnblogs.com/xp796/p/5236945.html https://www.cnblogs.com/MarcoHan/p/5295398.html - ...