Java Singleton Implementation
2024-10-18 20:23:18
概述
Java中单例模式的实现有多重方法, 要实现单例模式主要的问题是线程安全问题以及对Lazy Load的考虑,主要有如下几种
- 双重锁定懒加载单例
- 预加载单例
- 枚举单例
双重锁定懒加载单例模式
/**
* 双重锁定懒加载单例实现
*
* @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()方法每次都会返回一个新的示例
最新文章
- yii2实战教程之新手入门指南-简单博客管理系统
- 搭建高可用的rabbitmq集群 + Mirror Queue + 使用C#驱动连接
- 使用Packet Sniffer抓包和分析(z-stack协议)
- IO:OutPutStream
- 登录Cloudera Manager时报错org.hibernate.exception.GenericJDBCException: Could not open connection
- How to Programmatically Switch between the HubTile Visual States
- MySQL 5.7 SYS系统SCHEMA
- 新建txt文件新增内容并打印出
- 用MyGeneration模板生成NHibernate映射文件和关系
- 织梦内容管理系统(DedeCms) 小说模块insert注入漏洞
- Linux cd命令
- mpls vpn剩余笔记
- dom4j详解
- Go语言之闭包
- mysql insert锁机制
- 将电脑信息上传到中国移动ONENET平台
- js便签笔记(5)——Dean Edwards大牛的跨浏览器AddEvent()设计(不知道是不是jQuery事件系统的原型)
- 让服务器可以下载apk和ipa文件
- Python 文件 tell() 方法
- C#一个关于委托和事件通俗易懂的例子
热门文章
- P1679 神奇的四次方数
- 005.MySQL双主-Master01可用配置
- 22.python中的面向对象和类的基本语法
- DOM操作——JavaScript怎样添加、移除、移动、复制、创建和查找节点
- URAL 1962 In Chinese Restaurant 数学
- the difference between an embOS interrupt and a zero latency interrupt
- swap文件查看
- lodash用法系列(3),使用函数
- WCF X.509证书双向认证小结
- springboot之异步调用@Async