Introduction

单例模式在很多的框架中被广泛使用。

对于系统中的某个类来说,只有一个实例是很重要的,比如只能有一个timer和ID Producer。又比如在服务器程序中,配置信息保留在一个文件中,这些配置信息只由一个单例对象统一获取,进程中的其他对象通过这个单例对象获取这些配置信息,通过这种方式大大简化复杂环境下的配置管理。

这个时候一个类里面就只能有一个实例,并且这个实例要易于访问。我当然可以只定义一个全局变量从而保证对象随时都能访问。但是如果是这种方式来实现单例模式的话,依然可以实例化多个instance,而且被不同的对象所持有(这就违反了单例模式的条件了)不是很妙。

实现单例模式的思路是:

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

如果类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。

Definition

Singleton Pattern:单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。

  1. 单例类只能由一个实例
  2. 自行创建实例
  3. 自行向整个系统(所有其他对象)提供此实例

Attention

在多线程的应用场合中使用单例模式的时候要注意。如果唯一的单例尚未被创建(懒汉模式),有两个线程同时调用构建的方法,他俩都不会检测到唯一实例,于是每个线程都创建了一个实例,这就违反了单例模式中实例唯一的原则。

所以我们可以为指示类是否实例化的变量提供一个互斥锁。(会降低效率)

Java实现

常用的构建方式

  • 懒汉模式。指全局的单例模式在第一次使用时被创建。
  • 饿汉方式。指全局的单例模式在类装载的时候被创建。

Example

  1. 饿汉模式
public class Sington{
private static Singleton instance = new Singleton();
private Singleton (){
}
public static Singleton getInstance() {
return instance;
}
}

在类加载的时候完成初始化,所以类的加载速度会比较慢,但是可以很快的获取对象,优势在于不需要去考虑多线程的同步问题。

  1. 懒汉模式

    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 的语义)

  1. 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)的更多相关文章

  1. Java 设计模式(三)-单例模式(Singleton Pattern)

    1     概念定义 1.1   定义 确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 1.2   类型 创建类模式 1.3   难点 1)多个虚拟机 当系统中的单例类被拷贝运行在多 ...

  2. Java 基础:单例模式 Singleton Pattern

    1.简介 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创 ...

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

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

  4. Java设计模式之单例模式 - Singleton

    用来创建独一无二的,是能有一个实例的对象的入场券.告诉你一个好消息,单例模式的类图可以说是所有模式的类图中最简单的,事实上,它的类图上只有一个类!但是,可不要兴奋过头,尽管从类设计的视角来说很简单,但 ...

  5. java中的单例模式与静态类

    单例模式与静态类(一个类,所有方法为静态方法)是另一个非常有趣的问题,在<Java中有关单例模式的面试问题>博文中露掉了,由于单例模式和静态类都具有良好的访问性,它们之间有许多相似之处,例 ...

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

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

  7. 抽象工厂(Abstract Factory),工厂方法(Factory Method),单例模式(Singleton Pattern)

    在谈工厂之前,先阐述一个观点:那就是在实际程序设计中,为了设计灵活的多态代码,代码中尽量不使用new去实例化一个对象,那么不使用new去实例化对象,剩下可用的方法就可以选择使用工厂方法,原型复制等去实 ...

  8. 设计模式系列之单例模式(Singleton Pattern)——确保对象的唯一性

    模式概述 模式定义 模式结构图 饿汉式单例与懒汉式单例 饿汉式单例 懒汉式单例 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 主要优点 适用场景 说明:设计模式系列文章是读刘伟所著 ...

  9. 【设计模式】单例模式 Singleton Pattern

    通常我们在写程序的时候会碰到一个类只允许在整个系统中只存在一个实例(Instance)  的情况, 比如说我们想做一计数器,统计某些接口调用的次数,通常我们的数据库连接也是只期望有一个实例.Windo ...

  10. java中myeclipse连接mysql问题(java.lang.ClassNotFoundException: com.mysql.jdbc.Driver)

    java中myeclipse连接mysql问题(java.lang.ClassNotFoundException: com.mysql.jdbc.Driver) 1.往项目中添加mysql-conne ...

随机推荐

  1. mencache的使用二

    在这里说的是在C#中的使用,在C#中使用是需要引入驱动的, 可以在网上找,这里推荐一个链接http://sourceforge.net/projects/memcacheddotnet/ 将Memca ...

  2. java基础之super关键字

    一.在java里面,对于super关键字通常有两种用法: 1. 用在子类的构造方法里(初始化用),主要是调用父类的默认构造方法,如果父类有不止一个构造方法,可以通过super指定具体的构造函数,比如 ...

  3. MySQL5.7.19版本压缩包安装方式的一些坑

    ySQL社区版下载地址:https://dev.mysql.com/downloads/mysql/,在这里也可以选择之前的版本下载. MySQL进入5.7.7版本以后,压缩包安装需要注意一些地方: ...

  4. Wiki上的C++哲学

    Philosophy[edit] Throughout C++'s life, its development and evolution has been informally governed b ...

  5. ASP.NET 5 (vNext) 牛刀小試:自帶 DI 容器

    小引 在 ASP.NET 5(vNext)之前,亦即 MVC 4/5.Web API 2 的时代,MVC 与 Web API 框架彼此有非常相似的设计,却是以不同的代码来实现.现在,ASP.NET 5 ...

  6. Dependency Injection 筆記 (3)

    续上集.接着要来进一步了解的是 DI 的实现技术,也就是注入相依对象的方式.这里介绍的依赖注入方式,又称为「穷人的 DI」(poor man’s DI),因为这些用法都与特定 DI 工具无关,亦即不使 ...

  7. ansible(二)

    一.软件相关模块 1.yum(下载包) 正常操作 yum 与rpm的区别 yum可以解决依赖关系rpm 全称readhat package manager(红帽包管理工具),需要自己解决依赖 yum源 ...

  8. 利用Maven, 搭建最简单的SpringMVC框架

    本文介绍使用maven搭建SpringMVC最简单的框架程序过程,适合初学者上手. 文章下载

  9. JVM底层实现与总结

    一.类加载器 1.BootstrapClassLoader(启动类加载器) 它主要负责加载%JAVA_HOME%/jre/lib,-Xbootclasspath参数指定的路径以及%JAVA_HOME% ...

  10. PDF Expert for Mac v2.4.22 中文破解版下载 PDF阅读编辑软件

    PDF Expert for Mac v2.4.22 中文破解版下载:http://h5ip.cn/CsRN PDF Expert for Mac, iOS 上最好用的 PDF 编辑器之一,现在终于打 ...