概述

Java中单例模式的实现有多重方法, 要实现单例模式主要的问题是线程安全问题以及对Lazy Load的考虑,主要有如下几种

  1. 双重锁定懒加载单例
  2. 预加载单例
  3. 枚举单例

双重锁定懒加载单例模式

/**
* 双重锁定懒加载单例实现
*
* @author zhenwei.liu created on 2013 13-9-23 上午10:49
* @version 1.0.0
*/
public class DoubleCheckedLockingSingleton { private static volatile DoubleCheckedLockingSingleton INSTANCE;
private static Object lock = new Object(); private volatile Var var; /** 阻止用户实例化单例工厂 */
private DoubleCheckedLockingSingleton() {
var = new Var();
} public static DoubleCheckedLockingSingleton getInstance() {
if (INSTANCE == null) { //
synchronized (lock) {
if (INSTANCE == null) {
INSTANCE = new DoubleCheckedLockingSingleton(); //
}
}
}
return INSTANCE;
} public void getVar() {
return var; // 3
}
}

按照Happen-Before内存模型,  如果两个线程都进入了 synchronized 同步块, 则肯定能见到前一个同步块执行的内容, 但是由于出现下列情况

1. 线程 t1 执行 1 -> 2 代码序列

2. 线程 t2 执行 1, 然后发现INSTANCE不为空, 直接返回instance, 而并没有进入同步块, 这个时候由于没有happen-before的保证, 则 t2 在执行 3, 有可能获得的var为null(并没有看到t1在构造方法对var实例化的过程), 所以我们需要加上volatile, 这样就不会出现这个成员变量不一致的问题.

预加载单例

/**
* 预加载单例实现
*
* @author zhenwei.liu created on 2013 13-9-23 上午10:52
* @version 1.0.0
*/
public class NoneLazyLoadedSingleton { /** 加载类信息时实例化单例 */
private static NoneLazyLoadedSingleton INSTANCE = new NoneLazyLoadedSingleton(); /** 阻止用户实例化单例工厂 */
private NoneLazyLoadedSingleton() {} public static NoneLazyLoadedSingleton getInstance() {
return INSTANCE;
} public void action() {
System.out.println("do something");
}
}

枚举单例

/**
* 枚举的单例实现
*
* @author zhenwei.liu created on 2013 13-9-23 上午11:00
* @version 1.0.0
*/
public enum EnumSingleton implements Serializable {
INSTANCE; public void action() {
System.out.println("do something");
} /**
* readResolve()方法会在ObjectInputStream读取完对象准备返回前调用
* 如果定义了readResolve()方法,则由readResolve方法指定返回对象
*
* @return
*/
private Object readResolve() {
return INSTANCE;
}
}

枚举没有构造方法,它的每一个示例都是静态的单例,并且可以定义成员变量及其行为,可以说是纯天然的单例实现

需要注意的地方是对单例反序列化的时候,需要定义readResolve()方法,否则每次反序列化readObject()方法每次都会返回一个新的示例

最新文章

  1. yii2实战教程之新手入门指南-简单博客管理系统
  2. 搭建高可用的rabbitmq集群 + Mirror Queue + 使用C#驱动连接
  3. 使用Packet Sniffer抓包和分析(z-stack协议)
  4. IO:OutPutStream
  5. 登录Cloudera Manager时报错org.hibernate.exception.GenericJDBCException: Could not open connection
  6. How to Programmatically Switch between the HubTile Visual States
  7. MySQL 5.7 SYS系统SCHEMA
  8. 新建txt文件新增内容并打印出
  9. 用MyGeneration模板生成NHibernate映射文件和关系
  10. 织梦内容管理系统(DedeCms) 小说模块insert注入漏洞
  11. Linux cd命令
  12. mpls vpn剩余笔记
  13. dom4j详解
  14. Go语言之闭包
  15. mysql insert锁机制
  16. 将电脑信息上传到中国移动ONENET平台
  17. js便签笔记(5)——Dean Edwards大牛的跨浏览器AddEvent()设计(不知道是不是jQuery事件系统的原型)
  18. 让服务器可以下载apk和ipa文件
  19. Python 文件 tell() 方法
  20. C#一个关于委托和事件通俗易懂的例子

热门文章

  1. P1679 神奇的四次方数
  2. 005.MySQL双主-Master01可用配置
  3. 22.python中的面向对象和类的基本语法
  4. DOM操作——JavaScript怎样添加、移除、移动、复制、创建和查找节点
  5. URAL 1962 In Chinese Restaurant 数学
  6. the difference between an embOS interrupt and a zero latency interrupt
  7. swap文件查看
  8. lodash用法系列(3),使用函数
  9. WCF X.509证书双向认证小结
  10. springboot之异步调用@Async