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 ...
随机推荐
- springboot 2.x处理404、500等异常
404错误 404错误是不经过Controller的,所以使用@ControllerAdvice或@RestControllerAdvice无法获取到404错误 springboot2处理404错误的 ...
- Oracle 宣布 Java 7 生命周期终结
快速使用Romanysoft LAB的技术实现 HTML 开发Mac OS App,并销售到苹果应用商店中. <HTML开发Mac OS App 视频教程> 土豆网同步更新:http: ...
- 【DRP】-完成物料修改页面Servlet和JSP开发
本系列博客内容为:做DRP系统中的常用功能. 该项目采用MVC架构 C(Controller)控制器,主要职责;1.取得表单参数:2.调用业务逻辑:3.转向页面 M(Model)模型,主要职责:1.业 ...
- select Demo
#include <iostream> #include <WinSock2.h> using namespace std; #pragma comment(lib, &quo ...
- 多进程demo
多进程实现DOS重定向输出,界面如下: 主要的代码实现如下: #define MAXREADBUFFERLEN (60 * 1000) void CRedirectDlg::OnBnClickedBu ...
- hdu4633_Polya定理
典型的Polya定理,还算比较简单,比赛的时候知道是Polya定理但是根本没留出时间去搞,有点小遗憾. 思路:根据Burnside引理,等价类个数等于所有的置换群中的不动点的个数的平均值,根据Poly ...
- python中的内置函数(bytearray)
返回一个新的字节数组.bytearray类是range 0 < = x < 256的一个可变序列.它有大多数可变序列的常用方法,在可变序列类型中描述,以及大多数字节类型的方法,参见字节和B ...
- 30255Java_5.5 GUI
GUI GUI的各种元素(如:窗口,按钮,文本框等)由Java类来实现 1.AWT 使用AWT所涉及的类一般在java.awt包及其子包中 AWT(Abstract Window Toolkit)包括 ...
- 【linux杂谈】跟随大牛进行一次服务器间通讯问题的排查
发现应用记录日志内,出现网络访问延迟较大的情况. 此类问题较为常见,特别是之前参与辅助一个朋友项目运维的过程中,经常因为网络访问延迟较大,朋友认为是遭到了ddos攻击或者是cc攻击.网络访问延迟较大常 ...
- if while 条件语句练习题
1.使用while循环输入123456 8910 n = 1 while n < 11 if n == 7 pass else print(n) n= n + 1 2.求1-100内所有数的和. ...