Java设计模式4:单例模式
前言
非常重要,单例模式是各个Java项目中必不可少的一种设计模式。本文的关注点将重点放在单例模式的写法以及每种写法的线程安全性上。所谓"线程安全性"的意思就是保证在创建单例对象的时候不存在竞争,只会创建出一个单例对象。
单例模式
作为对象的创建模式,单例模式确保其某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类。单例模式有以下特点:
1、单例类只能有一个实例
2、单例类必须自己创建自己的唯一实例
3、单例类必须给其他所有对象提供这一实例
下面看一下单例模式的三种写法,除了这三种写法,静态内部类的方式、静态代码块的方式、enum枚举的方式也都可以,不过异曲同工,这三种方式就不写了。
饿汉式
顾名思义,饿汉式,就是使用类的时候不管用的是不是类中的单例部分,都直接创建出单例类,看一下饿汉式的写法:
public class EagerSingleton
{
private static EagerSingleton instance = new EagerSingleton(); private EagerSingleton()
{ } public static EagerSingleton getInstance()
{
return instance;
}
}
这就是饿汉式单例模式的写法,也是一种比较常见的写法。这种写法会不会造成竞争,引发线程安全问题呢?答案是不会。可能有人会觉得奇怪:
第3行,CPU执行线程A,实例化一个EagerSingleton,没有实例化完,CPU就从线程A切换到线程B了,线程B此时也实例化这个EagerSingleton,然后EagerSingleton被实例化出来了两次,有两份内存地址,不就有线程安全问题了吗?
没关系,我们完全不需要担心这个问题,JDK已经帮我们想到了。Java虚拟机2:Java内存区域及对象,文中可以看一下对象创建这一部分,没有写得很详细,其实就是"虚拟机采用了CAS配上失败重试的方式保证更新更新操作的原子性和TLAB两种方式来解决这个问题"。
懒汉式
同样,顾名思义,这个人比较懒,只有当单例类用到的时候才会去创建这个单例类,看一下懒汉式的写法:
public class LazySingleton
{
private static LazySingleton instance = null; private LazySingleton()
{ } public static LazySingleton getInstance()
{
if (instance == null)
instance = new LazySingleton();
return instance;
}
}
这种写法基本不用,因为这是一种线程非安全的写法。试想,线程A初次调用getInstance()方法,代码走到第12行,线程此时切换到线程B,线程B走到12行,看到instance是null,就new了一个LazySingleton出来,这时切换回线程A,线程A继续走,也new了一个LazySingleton出来。这样,单例类LazySingleton在内存中就有两份引用了,这就违背了单例模式的本意了。
可能有人会想,CPU分的时间片再短也不至于getInstance()方法只执行一个判断就切换线程了吧?问题是,万一线程A调用LazySingleton.getInstance()之前已经执行过别的代码了呢,走到12行的时候刚好时间片到了,也是很正常的。
双检锁
既然懒汉式是非线程安全的,那就要改进它。最直接的想法是,给getInstance方法加锁不就好了,但是我们不需要给方法全部加锁啊,只需要给方法的一部分加锁就好了。基于这个考虑,引入了双检锁(Double Check Lock,简称DCL)的写法:
public class DoubleCheckLockSingleton
{
private static DoubleCheckLockSingleton instance = null; private DoubleCheckLockSingleton()
{ } public static DoubleCheckLockSingleton getInstance()
{
if (instance == null)
{
synchronized (DoubleCheckLockSingleton.class)
{
if (instance == null)
instance = new DoubleCheckLockSingleton();
}
}
return instance;
}
}
双检锁的写法是不是线程安全的呢?是的,至于为什么,不妨以分析懒汉式写法的方式分析一下双检锁的写法。
线程A初次调用DoubleCheckLockSingleton.getInstance()方法,走12行,判断instance为null,进入同步代码块,此时线程切换到线程B,线程B调用DoubleCheckLockSingleton.getInstance()方法,由于同步代码块外面的代码还是异步执行的,所以线程B走12行,判断instance为null,等待锁。结果就是线程A实例化出了一个DoubleCheckLockSingleton,释放锁,线程B获得锁进入同步代码块,判断此时instance不为null了,并不实例化DoubleCheckLockSingleton。这样,单例类就保证了在内存中只存在一份。
单例模式在Java中的应用及解读
Runtime是一个典型的例子,看下JDK API对于这个类的解释"每个Java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接,可以通过getRuntime方法获取当前运行时。应用程序不能创建自己的Runtime类实例。",这段话,有两点很重要:
1、每个应用程序都有一个Runtime类实例
2、应用程序不能创建自己的Runtime类实例
只有一个、不能自己创建,是不是典型的单例模式?看一下,Runtime类的写法:
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
...
}
后面的就不黏贴了,到这里已经足够了,看到Runtime使用getRuntime()方法并让构造方法私有保证程序中只有一个Runtime实例且Runtime实例不可以被用户创建。
单例模式的好处
作为一种重要的设计模式,单例模式的好处有:
1、控制资源的使用,通过线程同步来控制资源的并发访问
2、控制实例的产生,以达到节约资源的目的
3、控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信
Java设计模式4:单例模式的更多相关文章
- java 设计模式之单例模式
-------Success is getting what you want, happiness is wanting what you get. java设计模式之单例模式(Singleton) ...
- 折腾Java设计模式之单例模式
博文原址:折腾Java设计模式之单例模式 单例模式 Ensure a class has only one instance, and provide a global point of access ...
- Java设计模式之单例模式(七种写法)
Java设计模式之单例模式(七种写法) 第一种,懒汉式,lazy初始化,线程不安全,多线程中无法工作: public class Singleton { private static Singleto ...
- Java 设计模式之单例模式(一)
原文地址:Java 设计模式之单例模式(一) 博客地址:http://www.extlight.com 一.背景 没有太多原由,纯粹是记录和总结自己从业以来经历和学习的点点滴滴. 本篇内容为 Java ...
- java设计模式1——单例模式
java设计模式1--单例模式 1.单例模式介绍 1.1.核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点 1.2.常见场景 1.3.单例模式的优点 1.4.常见的五种单例模式实现 ...
- java设计模式之单例模式你真的会了吗?(懒汉式篇)
java设计模式之单例模式你真的会了吗?(懒汉式篇) 一.什么是单例模式? 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供 ...
- java设计模式之单例模式(几种写法及比较)
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
- java设计模式- (1)单例模式
参加校园招聘的笔试,发现公司都会考一些java设计模式,所以上网查询相关内容,总结常用的几种单例模式. 单例模式(Singleton Pattern)是 Java中最简单的设计模式之一.这种类型的设计 ...
- [转]JAVA设计模式之单例模式
原文地址:http://blog.csdn.net/jason0539/article/details/23297037 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主 ...
- java设计模式之单例模式(七种方法)
单例模式:个人认为这个是最简单的一种设计模式,而且也是在我们开发中最常用的一个设计模式. 单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个 ...
随机推荐
- C# 京东模拟登录小结
最近有需要模拟京东登录,在解决过程中遇到了一些问题,因此这里记录下来避免以后遇到同样的问题. 首先第一步需要做的是找到登录请求网址和关于请求所需的一些信息.这里可以用抓取工具或者直接用firebug或 ...
- survey on Time Series Analysis Lib
(1)I spent my 4th year Computing project on implementing time series forecasting for Java heap usage ...
- 对象的比较与排序:IComparable和IComparer接口
IComparable和ICompare 接口是.net framework 中比较对象的标准方式,这两个接口提供一个返回值类似(大于0 等于0 小于0)的比较方法,二者区别如下: . ICompar ...
- js二维数组与字符串
1. 二维数组:数组中的元素,又引用了另一个数组对象 何时使用:只要保存横行竖列的数据, 具有上下级包含关系的数据, 创建二维数组: 1. var arr=[]; col arr[0]=[" ...
- PHP二维数组排序
$arrays 要排序的数组 $sort_key 根据排序的key $sort_order 升序降序 SORT_ASC/SORT_DESC $sort_type 排序key类型 SORT_N ...
- PostMan插件安装
一直没装上postman,今天运气好,竟装上了 给大家show一下吧,也希望大家跟我一样走弯路甚至于走不过去!:) 1.下载Postman_v4.1.3.rar,这个是我测试验证并打包的: 加QQ群: ...
- HttpURLConnection 文件上传限制
一. 问题 最近在Android程序里上传向.Net服务器上传大文件的时候,发现了一个问题.当上传大文件的时候会爆出OutOfMemoryError,上传小文件则没有这种情况. 二. ...
- ArcGIS Js/Flex等前端API(Query(StatisticDefinition)时)针对SDE的SHAPE.AREA/SHAPE.LEN知道查询无效,而对GDB的SHAPE_Area/SHAPE_Length有效探索。
FIeld 'SHAPE.AREA' and 'SHAPE.LEN' of SDE For Oracle,Field 'SHAPE_Area' and 'SHAPE_Length' of gdb(ge ...
- SAS提供的机器学习算法
SAS graphical user interfaces help you build machine-learning models and implement an iterative mach ...
- 关于mysql的access denied 错误解决方案
mysql -u root -p 按回车,输入密码后提示access denied......ues password YES/NO的错误? 第一步: 这时你需要进入/etc/mysql目录下,然后s ...