概念

引用维基百科对单例的说明:

单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在

继续引用维基百科的实现思路:

实现单例模式的思路是:一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。

单例的思路就这么简单,不像其他的设计模式那样一般有几个类。它只有一个类。

Java 中的单例实现

懒汉式与饿汉式

在讨论 Java 的单例模式时,猿们一般会提到两者实现方式:懒汉式饿汉式 。为什么会有这两种叫法?看了实现代码后,相信您会忽然大悟。

饿汉式,我是饿汉,不能等,创建(类)时就要给我吃的(实例化对象),不然我会饿死:

public class Singleton{
//创建类时就实例化出单例。
private final static Singleton INSTANCE = new Singleton(); //使用私有的构造器来阻止外部(其他代码)实例化该对象
private Singleton(){} //由于该类的构造方法是私有的,只能在该类内部实例化对象。因此必须提供一个静态的公有方法作为出口,提供单例。
public static Singleton getInstance(){
return INSTANCE;
}
}

懒汉式, 我是懒汉,你叫我干活(给 INSTANCE new 一个单例)才干,懒是我的天性,这不能怪我:

public class Singleton{
private static Singleton INSTANCE; private Singleton(){} public static Singleton getInstance(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
}

OK,单例模式就是这么简单,结束了。呵呵,真的结束了吗?图样图森破!

上面的两个实现确实是实现了汉式和懒汉式。而且它们在单线程下能很好地运行。但如果我们把它们应用在多线程下呢?试一下就知道,饿汉式依然坚挺,潇洒应对。但懒汉式就瞬间爆炸了!没办法谁叫你懒,出来混总是要还的。即使是代码,懒也要付出代价~~开玩笑的_,爆炸的原因肯定不是懒的原因啦,是线程同步的问题,造成了非线程安全的懒汉式。

既然上面的懒汉式在多线程下爆炸了,我们就要去拯救它,总不能见死不救吧~~

多线程下懒汉式的自我拯救

知道懒汉式爆炸的原因时线程同步的问题,我们最简单的拯救方法就是直接进行同步加锁,创建线程安全的懒汉式

public class Singleton{
private static Singleton INSTANCE; private Singleton(){} public static synchronized Singleton getInstance(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
}

通过简单的对 getInstance 方法进行加锁就可以把非线程安全的懒汉式改为线程安全的,简单吧!但,正如天下没免费的午餐一样,如此简单的拯救方法肯定是要付出代价的。因此这种实现方法会降低效率。

好吧,效率低下,我改还不行。经过改改改后,我们又得出了另外一种线程安全懒汉式单例:双重校验锁(Double-Checked Locking)

public class Singleton{
private static volatile Singleton INSTANCE; private Singleton(){} public static Singleton getInstance(){
if(INSTANCE == null){
synchronized(Singleton.class){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}

该方法比之前的线程安全懒汉式效率高的原因是,之前的实现方法每次获取单例是都要进行同步,每一次只能有一个线程进入 getInstance 方法获取实例;而该方法把同步块缩小了,而且只在 INSTANCE 为 null 时才会进行同步访问(也就是说只需要一次同步)。之后都不需要同步,可以并发地获取实例。

很多人都知道,JDK 1.5 之前利用这种方法实现是有问题的。但在 JDK 1.5 后,Java 的内存已经修改了,该方法在 1.5 后能正常运行,可以放心使用。

其他的实现方法

使用静态内部类实现

public class Singleton{
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
} private Singleton(){} public static final Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}

该方法利用了静态内部类的特性实现了类似与懒汉式的单例模式

(单元素的)枚举实现

public enum Singleton{
INSTANCE;
}

枚举实现的单例已经简单到不能再简单了,可以直接使用 Singleton.INSTANCE 来获取单例。它虽然简单,但也是线程安全的实现方法,并且也是可序列化的。在 Effective Java 第二版里也推荐使用这种方法: 单元素的枚举类型已经成为实现 Singleton 的最佳方法

单例在 Java 中的应用

  • Java.awt.Toolkit with getDefaultToolkit()
  • Java.awt.Desktop with getDesktop()
  • java.lang.Runtime

java.lang.Runtime 使用的单例(饿汉式,不涉及到线程安全):

public class Runtime{
private static Runtime currentRuntime = new Runtime(); public static Runtime getRuntime(){
return currentRuntime;
} private Runtime(){} //... 其他方法
}

参考

维基百科

StackExchange

使用枚举实现单例

Effective Java 第三条建议

单例模式(Singleton)小记的更多相关文章

  1. 设计模式之单例模式——Singleton

                        设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有 ...

  2. 【白话设计模式四】单例模式(Singleton)

    转自:https://my.oschina.net/xianggao/blog/616385 0 系列目录 白话设计模式 工厂模式 单例模式 [白话设计模式一]简单工厂模式(Simple Factor ...

  3. ooad单例模式-Singleton

                                                单例模式Singleton 主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 比如建立目录 ...

  4. iOS单例模式(Singleton)写法简析

    单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 1.单例模式的要点: 显然单例模式的要点有三个:一是某个类只能有一个实例: ...

  5. 浅谈设计模式--单例模式(Singleton Pattern)

    题外话:好久没写blog,做知识归纳整理了.本来设计模式就是个坑,各种文章也写烂了.不过,不是自己写的东西,缺少点知识的存在感.目前还没做到光看即能记住,得写.所以准备跳入设计模式这个大坑. 开篇先贡 ...

  6. 设计模式之——单例模式(Singleton)的常见应用场景

    单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...

  7. 设计模式之单例模式(Singleton Pattern)

    单例模式 单例模式(Singleton Pattern)在java中算是最常用的设计模式之一,主要用于控制控制类实例的数量,防止外部实例化或者修改.单例模式在某些场景下可以提高系统运行效率.实现中的主 ...

  8. 设计模式(4) -- 单例模式(Singleton)

    设计模式(4)  -- 单例模式(Singleton) 试想一个读取配置文件的需求,创建完读取类后通过New一个类的实例来读取配置文件的内容,在系统运行期间,系统中会存在很多个该类的实例对象,也就是说 ...

  9. IOS单例模式(Singleton)

    IOS单例模式(Singleton)   单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 1.单例模式的要点: 显然单例模 ...

  10. java设计模式之 单例模式 Singleton

    static 的应用 单例模式 Singleton 单例:保证一个类在系统中最多只创建一个实例. 好处:由于过多创建对象实例,会产生过多的系统垃圾,需要GC频繁回收,由于GC会占用较大的系统资源,所有 ...

随机推荐

  1. 搞点事情,使用node搭建反向代理

    导语 最近有个需求,需要对业务管理后台的操作记录进行上报.一般这种上报需求都是又后台同学来做比较合适的.但是因为后台人力的原因.这个工作落到了我这个小前端的头上.这里记录下做这个需求踩的一些坑. 一. ...

  2. Redis作为缓存服务器

    1.ICache的Redis实现没有放在'Framework.Cache/Logic'中.如果是以前,我会认为这样不好.我会这样做,'Framework.Cache'项目引用Redis项目或直接从Nu ...

  3. Asp .net core api+Entity Framework core 实现数据CRUD数据库中(附Git地址)

    最近在学dotNetCore 所以尝试了一下api 这个功能 不多说了大致实现如下 1.用vs2017建立一个Asp.net  Core Web 应用程序 在弹出的对话框中选择 Web API 项目名 ...

  4. Ubuntu下配置eclipse环境

    一.安装JDK,配置Java环境变量 1.下载JDK,Java SE 8的官方网址是http://www.oracle.com/technetwork/java/javase/downloads/jd ...

  5. Delphi 三层框架开发 服务端开发

    采用Delphi7+SQL2008 一.创建数据库和表 CREATE TABLE [dbo].[tb_Department]( [FKey] [uniqueidentifier] NOT NULL, ...

  6. onload函数和自执行函数的区别(jquery API网址:http://jquery.cuishifeng.cn/)

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  7. 【jdbc】【c3p0】c3p0三种配置方式【整理】

    c3p0三种配置方式 c3p0的配置方式分为三种,分别是1.setters一个个地设置各个配置项2.类路径下提供一个c3p0.properties文件3.类路径下提供一个c3p0-config.xml ...

  8. Shaders

    [Shaders] 1.Vertex-Lit,顶点光照着色器. Vertex-Lit is one of the simplest shaders. All lights shining on it ...

  9. cdoj525-猴子选大王 (约瑟夫环)

    http://acm.uestc.edu.cn/#/problem/show/525 猴子选大王 Time Limit: 3000/1000MS (Java/Others)     Memory Li ...

  10. 高性能Web服务器Nginx的配置与部署研究(7)核心模块之主模块的非测试常用指令

    1. error_log 含义:指定存储错误日志的文件 语法:error_log <file> [debug|info|notice|warn|error|crit] 缺省:${prefi ...