前言

非常重要,单例模式是各个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:单例模式的更多相关文章

  1. java 设计模式之单例模式

    -------Success is getting what you want, happiness is wanting what you get. java设计模式之单例模式(Singleton) ...

  2. 折腾Java设计模式之单例模式

    博文原址:折腾Java设计模式之单例模式 单例模式 Ensure a class has only one instance, and provide a global point of access ...

  3. Java设计模式之单例模式(七种写法)

    Java设计模式之单例模式(七种写法) 第一种,懒汉式,lazy初始化,线程不安全,多线程中无法工作: public class Singleton { private static Singleto ...

  4. Java 设计模式之单例模式(一)

    原文地址:Java 设计模式之单例模式(一) 博客地址:http://www.extlight.com 一.背景 没有太多原由,纯粹是记录和总结自己从业以来经历和学习的点点滴滴. 本篇内容为 Java ...

  5. java设计模式1——单例模式

    java设计模式1--单例模式 1.单例模式介绍 1.1.核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点 1.2.常见场景 1.3.单例模式的优点 1.4.常见的五种单例模式实现 ...

  6. java设计模式之单例模式你真的会了吗?(懒汉式篇)

    java设计模式之单例模式你真的会了吗?(懒汉式篇) 一.什么是单例模式? 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供 ...

  7. java设计模式之单例模式(几种写法及比较)

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  8. java设计模式- (1)单例模式

    参加校园招聘的笔试,发现公司都会考一些java设计模式,所以上网查询相关内容,总结常用的几种单例模式. 单例模式(Singleton Pattern)是 Java中最简单的设计模式之一.这种类型的设计 ...

  9. [转]JAVA设计模式之单例模式

    原文地址:http://blog.csdn.net/jason0539/article/details/23297037 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主 ...

  10. java设计模式之单例模式(七种方法)

    单例模式:个人认为这个是最简单的一种设计模式,而且也是在我们开发中最常用的一个设计模式. 单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个 ...

随机推荐

  1. iscsi: 多路径

    作者:吴香伟 发表于 2014/10/8 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 上图(a)给出了计算机的总线结构,SCSI磁盘挂在SCSI卡上,SCSI ...

  2. PoEduo - C++阶段班【Po学校】-Lesson03-5_运算符重载- 第7天

    PoEduo - Lesson03-5_运算符重载- 第7天 复习前面的知识点 空类会自动生成哪些默认函数 6个默认函数    1  构造  2  析构   3  赋值  4 拷贝构造  5 oper ...

  3. HMC V7.9.0升级至SP2版本

    补丁下载地址:http://www-933.ibm.com/support/fixcentral/ 选择补丁版本 MH01405是和ftp://ftp.software.ibm.com/softwar ...

  4. 基于现有数据库的Code First模式迁移更新数据库

    本文讨论的内容是基于EF4.1版本.文中谈论的现有的数据库不是由EF创建.本文假定你已经对Code First迁移有一定的了解,如果不了解Code First迁移更新数据库可以查看 文章涉及的主题如下 ...

  5. maven认证信息

    上传至本地文件夹 <distributionManagement>         <repository>             <id>test</id ...

  6. 性能测试之--Apache JMeter安装

    Hi,今天给大家分享一下安装JMeter的相关内容~ Apache JMeter 是Apache组织的开源项目,是一个100%纯Java桌面应用,用于压力测试和性能测试. 它能够对HTTP.FTP服务 ...

  7. SharePoint 2013开发入门探索(二)- 列表操作

    我们如何用代码对SharePoint列表做些例如增删改查的操作呢?如果您的程序可以部署到服务器上,就可以使用 服务器对象模型,因为服务器对象模型提供的功能最多,限制最少:否则可能要选择客户对象模型等其 ...

  8. luogu p1268 树的重量——构造,真正考验编程能力

    题目链接:http://www.luogu.org/problem/show?pid=1268#sub -------- 这道题费了我不少心思= =其实思路和标称毫无差别,但是由于不习惯ACM风格的题 ...

  9. PHP使用XHProf进行性能分析

    1. 编译安装 wget http://pecl.php.net/get/xhprof-0.9.3.tgz tar zxvf xhprof-0.9.3.tgz cd xhprof-0.9.3/exte ...

  10. IQD文件模板以及cs7g.ini信息

    COGNOS QUERY STRUCTURE,1,1 DATABASE, cognos TITLE,test BEGIN SQL { select time, city_id, city_name, ...