1.描述:

Singleton(单例)是设计模式的一种,为了保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2.主要特点:

1)单例类确保自己只有一个实例(构造函数私有:不被外部实例化,也不被继承)。

2)单例类必须自己创建自己的实例。

3)单例类必须为其他对象提供唯一的实例。

3.单例模式的应用:

资源管理器,回收站,打印机资源,线程池,缓存,配置信息类,管理类,控制类,门面类,代理类通常被设计为单例类

如果程序有多个类加载器又同时使用单例模式就有可能多个单例并存就要找相应解决方法了

4.实现方法:

如果应用程序总是创建并使用单例实例或在创建和运行时开销不大。

1).Eager initialization 饿汉式单例类(依赖jvm在加载类时创建唯一单例实例)

public class EagerSingleton {  // jvm保证在任何线程访问uniqueInstance静态变量之前一定先创建了此实例  private static EagerSingleton uniqueInstance = new EagerSingleton();  // 私有的默认构造子,保证外界无法直接实例化  private EagerSingleton() {  }  // 提供全局访问点获取唯一的实例  public static EagerSingleton getInstance() {  return uniqueInstance;  }
}

如果开销比较大,希望用到时才创建就要考虑延迟实例化,或者Singleton的初始化需要某些外部资源(比如网络或存储设备),就要用后面的方法了.

2)Lazy initialization 懒汉式单例类

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

同步一个方法可能造成程序执行效率下降100倍,完全没有必要每次调用getInstance都加锁,事实上我们只想保证一次初始化成功,其余的快速返回而已,如果在getInstance频繁使用的地方就要考虑重新优化了.

3)"双检锁"(Double-Checked Lock)尽量将"加锁"推迟,只在需要时"加锁"(仅适用于java 5.0 以上版本,volatile保证原子操作) 
happens-before:"什么什么一定在什么什么之前运行",也就是保证顺序性.
现在的CPU有乱序执行的能力(也就是指令会乱序或并行运行,可以不按我们写代码的顺序执行内存的存取过程),并且多个CPU之间的缓存也不保证实时同步,只有上面的happens-before所规定的情况下才保证顺序性.

JVM能够根据CPU的特性(CPU的多级缓存系统、多核处理器等)适当的重新排序机器指令,使机器指令更符合CPU的执行特点,最大限度的发挥机器的性能.

如果没有volatile修饰符则可能出现一个线程t1的B操作和另一线程t2的C操作之间对instance的读写没有happens-before,可能会造成的现象是t1的B操作还没有完全构造成功,但t2的C已经看到instance为非空,这样t2就直接返回了未完全构造的instance的引用,t2想对instance进行操作就会出问题.

volatile 的功能:
1. 避免编译器将变量缓存在寄存器里  
2. 避免编译器调整代码执行的顺序

优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

public class DoubleCheckedLockingSingleton {  // java中使用双重检查锁定机制,由于Java编译器和JIT的优化的原因系统无法保证我们期望的执行次序。  // 在java5.0修改了内存模型,使用volatile声明的变量可以强制屏蔽编译器和JIT的优化工作  private volatile static DoubleCheckedLockingSingleton uniqueInstance;  private DoubleCheckedLockingSingleton() {  }  public static DoubleCheckedLockingSingleton getInstance() {  if (uniqueInstance == null) {  synchronized (DoubleCheckedLockingSingleton.class) {  if (uniqueInstance == null) {  uniqueInstance = new DoubleCheckedLockingSingleton();  }  }  }  return uniqueInstance;  }
}  

4)Lazy initialization holder class 满足所有 Double-Checked Locking 满足的条件,并且没有显示的同步操作

public class LazyInitHolderSingleton {  private LazyInitHolderSingleton() {  }  private static class SingletonHolder {  private static final LazyInitHolderSingleton INSTANCE = new LazyInitHolderSingleton();  }  public static LazyInitHolderSingleton getInstance() {  return SingletonHolder.INSTANCE;  }
}  
根据jvm规范,当某对象第一次调用LazyInitHolderSingleton.getInstance()时,LazyInitHolderSingleton类被首次主动使用,jvm对其进行初始化(此时并不会调用LazyInitHolderSingleton()构造方法),然后LazyInitHolderSingleton调用getInstance()方法,该方法中,又首次主动使用了SingletonHolder类,所以要对SingletonHolder类进行初始化,初始化中,INSTANCE常量被赋值时才调用了 LazyInitHolderSingleton的构造方法LazyInitHolderSingleton(),完成了实例化并返回该实例。
当再有对象(也许是在别的线程中)再次调用LazyInitHolderSingleton.getInstance()时,因为已经初始化过了,不会再进行初始化步骤,所以直接返回INSTANCE常量即同一个LazyInitHolderSingleton实例。

singleton模式四种线程安全的实现相关推荐

  1. [转]new Thread的弊端及Java四种线程池的使用

    介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端 执行一个异步任务你还只是如下new ...

  2. Java ExecutorService四种线程池的例子与说明

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() {@Overridepublic void run() {// ...

  3. Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor...

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java new Thread(new Runnable() {@Override public void run ...

  4. java中四种线程池及poolSize、corePoolSize、maximumPoolSize

    目录 ThreadPoolExecutor重要参数 poolSize.corePoolSize.maximumPoolSize 四种线程池 newFixedThreadPool newCachedTh ...

  5. Java通过Executors提供四种线程池

    http://cuisuqiang.iteye.com/blog/2019372 Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如 ...

  6. java 线程工厂_Java并发编程:Java的四种线程池的使用,以及自定义线程工厂

    引言 通过前面的文章,我们学习了Executor框架中的核心类ThreadPoolExecutor ,对于线程池的核心调度机制有了一定的了解,并且成功使用ThreadPoolExecutor 创建了线 ...

  7. Java多线程系列(五):线程池的实现原理、优点与风险、以及四种线程池实现

    为什么需要线程池 我们有两种常见的创建线程的方法,一种是继承Thread类,一种是实现Runnable的接口,Thread类其实也是实现了Runnable接口.但是我们创建这两种线程在运行结束后都会被 ...

  8. Java 四种线程池的用法分析

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() {@Overridepublic void run() {// ...

  9. Java 四种线程池

    原文 介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端 执行一个异步任务你还只是如下n ...

最新文章

  1. 【神仙题】【P4885】 灭顶之灾
  2. 配置安全的Impala集群集成Sentry
  3. 图解Win32汇编字符串和Debug输出
  4. MyBatis-学习笔记05【05.使用Mybatis完成CRUD】
  5. 女生心中的理想男生!这些条件你符合几条?
  6. mysql快速上手3
  7. poll函数实现多路复用
  8. linux脚本初尝滋味-----编写与执行
  9. 华为云数据库携新品惊艳亮相2019华为全联接大会
  10. Java基础学习总结(175)——分布式ID的9种生成方式总结
  11. 谷歌用AI诊断早期肺癌超越人类医生,登上Nature子刊
  12. 梦想旅行出席中国互联网大会 做旅游界的技术派
  13. 简记_高频变压器基础知识(一)
  14. 2019-CS224n-Assignment1
  15. 在线二进制转文本字符工具
  16. 矩和质心之积分的应用
  17. oracle 落落是谁,落落是老虎妖精吗?落落的父母是什么身份?
  18. Matlab GUI编程技巧(八):uitoolbar在图窗中创建工具栏
  19. Linux局域网共享打印机(实用型文档)
  20. matlab中duration是什么意思,C++ duration(STL duration)模板用法详解

热门文章

  1. Windows 64位下为wampserver或phpstudy安装Redis扩展
  2. TCP 连接断连问题剖析
  3. 面对 20 亿行代码,Google 如何管理?
  4. hybird 跨平台移动app开发
  5. Android 模糊效果
  6. 【Ubuntu】Windows硬盘安装Ubuntu14.04
  7. PostGIS_导入shp格式的数据
  8. C语言实现一种简单的应用服务器内部数据结构的思路(三)
  9. NETCF平台下利用XmlSerializer对于复杂类型序列化的探索(三)
  10. android分析windowManager、window、viewGroup之间关系