单例模式

定义: 确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

类型: 创建类模式

类图:

单例模式特点

1、单例类只能有一个实例。

2、单例类必须自己创建自己的唯一实例。

3、单例类必须给所有其他对象提供这一实例。

单例模式应该是23种设计模式中最简单的一种模式了。它有以下几个要素:

  • 私有的构造方法
  • 指向自己实例的私有静态引用
  • 以自己实例为返回值的静态的公有的方法

单例模式的实现方式

单例模式根据实例化对象时机的不同分为两种:

一种是饿汉式单例,一种是懒汉式单例。

饿汉式单例在单例类被加载时候,就实例化一个对象交给自己的引用;

懒汉式在调用取得实例方法的时候才会实例化对象。

1)饿汉式单例

是否 Lazy 初始化:否
是否多线程安全:是
实现难度:易
描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
/**
* 饿汉式单例
* <p>
* 饿汉式是典型的空间换时间,当类装载的时候就会创建类的实例,
* 不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断,节省了运行时间。
*
* @author kaifeng
*/
public class HungrySingleton {
private static HungrySingleton hungrySingleton = new HungrySingleton(); /**
* 私有构造函数
*/
private HungrySingleton() {
} /**
* 获取实例对象
*/
public static HungrySingleton getInstance() {
return hungrySingleton;
}
}

2)懒汉式单例

是否 Lazy 初始化:是
是否多线程安全:是
实现难度:易
描述:这种单例是典型的时间换空间,只有使用的时候才会实例化,但是每次获取实例的时候都会进行判断,是否已经实例,花费了一些判断时间,如果一直没有使用就不会实例化,节省了内存空间
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
/**
* 懒汉式单例
* <p>
* 这种单例是典型的时间换空间,只有使用的时候才会实例化,但是每次获取实例的时候都会进行判断,
* 是否已经实例,花费了一些判断时间,如果一直没有使用就不会实例化,节省了内存空间
*
* @author kaifeng
*/
public class LazySingleton {
private static LazySingleton instance = null; /**
* 私有构造函数
*/
private LazySingleton() {
} /**
* 静态工厂方法,实例化对象
*/
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}

3)双检锁/双重校验锁(DCL,即 double-checked locking)

是否 Lazy 初始化:是
是否多线程安全:是
实现难度:较复杂
描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
/**
* 双检锁/双重校验锁(DCL,即 double-checked locking)
*
* @author kaifeng
*/
public class DCLSingleton { private volatile static DCLSingleton instance; private DCLSingleton() {
} public static DCLSingleton getInstance() {
//第一次检查实例是否存在,如果不存在才进入下面的同步块,否则直接返回实例
if (instance == null) {
//同步代码块,线程安全的创建实例
synchronized (DCLSingleton.class) {
//第二次检查实例是否存在,如果不存在才真正的创建实例
if (instance == null) {
instance = new DCLSingleton();
}
}
}
return instance;
}
}

所谓“双重检查加锁”机制:并不是每次进入getInstance方法都需要同步,而是先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。

“双重检查加锁”机制的实现会使用关键字volatile,被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。

4)Initialization-on-demand holder idiom

是否 Lazy 初始化:是
是否多线程安全:是
实现难度:一般
描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
/**
* 在这个类级内部类里面去创建对象实例,只要不使用到这个类级内部类,
* 那就不会创建对象实例,从而同时实现延迟加载和线程安全。
*
* @author kaifeng
*/
public class Singleton {
private Singleton() {
} /**
* 类级的内部类,就是静态的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定关系,而且只有被调用时才会装载,从而实现了延迟加载。
*/
private static class SingletonHolder {
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static Singleton instance = new Singleton();
} public static Singleton getInstance() {
return SingletonHolder.instance;
}
}

当getInstance方法第一次被调用的时候,第一次读取SingletonHolder.instance,导致SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。

这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。

5)枚举

是否 Lazy 初始化:否
是否多线程安全:是
实现难度:易
描述:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
不能通过 reflection attack 来调用私有构造方法。
/**
* @author kaifeng
*/
public enum EnumSingleton {
/**
* 定义一个枚举的元素,它就代表了Singleton的一个实例
*/
instance; /**
* 单例可以有自己的操作
*/
public void singletonCustom() {
//自定义操作
}
}

单例模式的优点:

  • 在内存中只有一个对象,节省内存空间。
  • 避免频繁的创建销毁对象,可以提高性能。
  • 避免对共享资源的多重占用。
  • 可以全局访问。

适用场景:

  • 需要频繁实例化然后销毁的对象。
  • 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
  • 有状态的工具类对象。
  • 频繁访问数据库或文件的对象。
  • 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器

单例模式注意事项:

  • 只能使用单例类提供的方法得到单例对象,不要使用反射,否则将会实例化一个新对象。
  • 不要做断开单例类对象与类中静态引用的危险操作。
  • 多线程使用单例使用共享资源时,注意线程安全问题。

【java设计模式】-04单例模式的更多相关文章

  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. 论文阅读:《Bag of Tricks for Efficient Text Classification》

    论文阅读:<Bag of Tricks for Efficient Text Classification> 2018-04-25 11:22:29 卓寿杰_SoulJoy 阅读数 954 ...

  2. ACCESS打得开mdb,但打不开表,弹框提示未知错误。

    我的电脑有个一个奇怪的错误ACCESS能打开mdb数据库,但是打不开表,一打开就提示错误,只有俩字“未知”.重装OFFICE也不行!而且电脑上使用Access数据库的应用软件都不行了!都提示“未知”错 ...

  3. flutter问题集锦

    现在的多平台开发很多啦,目前主流的救赎react native 和weex了,其他的旧的就不说了,新出来的gomobile目前基本无人使用,底层的很多原生对接还没有完善,flutter发布了第一版正式 ...

  4. iphone SprintBoard部分私有API总结(不支持iOS8)

    本文介绍iOS SrpintBoard框架的部分私有API,具体包括: 获取ios上当前正在运行的所有App的bundle id(不管当前程序是在前台还是后台都可以) 获取ios上当前前台运行的App ...

  5. vue项目中图片预览旋转功能

    最近项目中需要在图片预览时,可以旋转图片预览,在网上找了下,发现有一款功能强大的图片组件:viewerjs. git-hup: https://github.com/fengyuanchen/view ...

  6. ASE19团队项目alpha阶段model组 scrum7 记录

    本次会议于11月11日,19时整在微软北京西二号楼sky garden召开,持续15分钟. 与会人员:Jiyan He, Kun Yan, Lei Chai, Linfeng Qi, Xueqing ...

  7. Git修改已经提交的用户名信息

    由于工作或者其他原因,有时候我们会修改git的用户名和邮箱账号,没有改过来就提交,就会导致提交人信息不一致的问题.现在记录修正回来的方法 # 第一步,(n)代表提交次数 git rebase -i H ...

  8. java线程基础巩固---如何实现一个自己的显式锁Lock

    拋出synchronized问题: 对于一个方法上了同锁如果被一个线程占有了,而假如该线程长时间工作,那其它线程不就只能傻傻的等着,而且是无限的等这线程工作完成了才能执行自己的任务,这里来演示一下这种 ...

  9. 自定义ViewGroup基础巩固2---onMeasure()学习及综合实现圆形菜单

    上次对自定义ViewGroup中的onLayout()方法进行了基础巩固[http://www.cnblogs.com/webor2006/p/7507284.html],对于熟知自定义ViewGro ...

  10. java中的集合总结

    知识点: 集合框架和List.set.Map相关集合特点的描述 Collection接口常用方法,List中相对Collection新增的方法,Collection的遍历(一般for循环,增强for循 ...