概念

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

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

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

实现单例模式的思路是:一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用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. LeetCode题解 #8 String to Integer (atoi)

    又是一道恶心的简单题. 一开始没想到这么多情况的,幸好LeetCode是个很人性化的oj,能让你知道你在哪个case上错了,否则一辈子都过不了. 考虑不周到只能一个个补了. 列举一下恶心的case / ...

  2. vue 起步_code

    <template> <div class="hello"> <h1>{{ msg }}</h1> <div>{{dat ...

  3. jena读取和解析本体文件

    使用jena开发本体应用程序时,首先需要对我们利用本体构建工具,如protege等,构建的本体文件,如owl.rdf等读取并解析得到本体模型.下面给出相应的代码,不对的地方请指正. (基于jena 2 ...

  4. lucene3.0范围查找

    在lucene3.0以上版本中,范围查询也有很大的变化,RangeQuery已经不推荐使用,使用TermRangeQuery和NumericRangeQuery两个替代.TermRangeQuery: ...

  5. 网络编程基础之Socket套接字

    一.Socket介绍 1.什么是socket? Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族 ...

  6. flask 启动

    export SECRET_KEY=qq77aa88 export MAIL_SERVER=smtp.qq.com export MAIL_USERNAME=591867837@qq.com expo ...

  7. Android开发实战之ViewPager实现向导界面

    当我们更新应用,或者第一次进入应用时都会有一个向导界面,介绍这个app的内容和使用方式. 如果你细心你会发现其实这就是个viewpager,本篇博文将介绍应用的向导界面是如何制作的.希 望本篇博文对你 ...

  8. php设置错误,错误记录

    //设置错误级别. error_reporting(E_ALL);  //显示所有错误 error_reporting(E_ALL&~E_NOTICE);  //显示所有错误但不显示提示级别的 ...

  9. Opencv threshold

    图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果.在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓 ...

  10. Logger Rate Limiter 十秒限时计数器

    [抄题]: Design a logger system that receive stream of messages along with its timestamps, each message ...