如何创建多线程环境下的可序列化单例模式
来源:互联网 发布:r9s怎么清除相机数据 编辑:程序博客网 时间:2024/05/16 17:00
本文从以下几个点讲解:
- 实现单例的两种方式(预加载&懒加载)
- 多线程环境下的单例
- 可序列化的单例
- 对以上代码的重构
- 单例与枚举
1. 实现单例的两种方式
预加载:
public class Foo { private static final Foo INSTANCE = new Foo(); private Foo() { if(INSTANCE != null) { throw new IllegalStateException("Already instantiated"); } } public static Foo getInstance() { return INSTANCE; }}
懒加载:
class Foo { private static Foo INSTANCE = null; private Foo() { if(INSTANCE != null) { throw new IllegalStateException("Already instantiated"); } } public static Foo getInstance() { if(INSTANCE == null) { INSTANCE = new Foo(); } return INSTANCE; }}
2. 多线程环境下的单例
上面的代码在单线程的情况下可以满足需要,如果在多线程环境下,则需要进行修改:
class Foo { // 请注意volatile关键字 private static volatile Foo INSTANCE = null; private Foo() { if(INSTANCE != null) { throw new IllegalStateException("Already instantiated"); } } public static Foo getInstance() { if(INSTANCE == null) { // check 1 synchronized(Foo.class) { if(INSTANCE == null) { // check 2 INSTANCE = new Foo(); } } } return INSTANCE; }}
3. 可序列化的单例
解决了多线程环境下的单例,可以进一步的思考如何实现可序列化的单例。反序列化可以不通过构造函数直接生成一个对象,所以反序列化时,我们需要保证其不再创建新的对象。
关于序列化的详细文章:click me
class Foo implements Serializable { private static final long serialVersionUID = 1L; private static volatile Foo INSTANCE = null; private Foo() { if(INSTANCE != null) { throw new IllegalStateException("Already instantiated"); } } public static Foo getInstance() { if(INSTANCE == null) { synchronized(Foo.class) { if(INSTANCE == null) { INSTANCE = new Foo(); } } } return INSTANCE; } @SuppressWarnings("unused") private Foo readResolve() { return INSTANCE; }}
readResolve方法可以保证,即使程序在上一次运行时序列化过此单例,也只会返回全局唯一的单例。
4. 对以上代码重构
public class Foo implements Serializable { private static final long serialVersionUID = 1L; // 使用内部静态class实现懒加载 private static class FooLoader { // 保证在多线程下无差错运行 private static Foo INSTANCE = new Foo(); } private Foo() { throw new UnsupportedOperationException("can not construct this Foo"); } public static Foo getInstance() { return FooLoader.INSTANCE; } @SuppressWarnings("unused") private Foo readResolve() { return FooLoader.INSTANCE; }}
5. 单例与枚举
最后提供一种更加简洁的方法:
public enum Foo { INSTANCE;}
08年 google 开发者年会中,Joshua Bloch Joshua Bloch 在 高效 Java 话题中解释了这种方法,视频请戳 这里,在他 演讲的ppt 30-32 页提到:
// 实现单例正确的方式如下:public enum Elvis { INSTANCE; private final String[] favoriteSongs = { "Hound Dog", "Heartbreak Hotel" }; public void printFavorites() { System.out.println(Arrays.toString(favoriteSongs)); }}
在 Effective Java 线上部分 说到:
上述实现单例的方式,其实等同于将 INSTANCE 设置为 public static final 的方式。
不同之处在于,使用枚举的方式显得更为简洁,而且枚举默认提供了序列化机制,也保证了多线程访问的安全。
虽然这种单例的实现方式还没有被广泛使用,但是实现单例的最好方式就是使用一个单元素的枚举。
为什么可以这么简洁?
因为 Java 中每一个枚举类型都默认继承了 java.lang.Enum,而 Enum 实现了 Serializable 接口,所以枚举类型对象都是默认可被序列化的。
通过反编译,也可以知道枚举常量本质上是一个pubilc static final xxx
关于序列化的详细文章:click me
阅读全文
0 0
- 如何创建多线程环境下的可序列化单例模式
- 可序列化单例模式的遗留问题答案
- 如何在unix c++环境下创建多线程呢?
- Java设计模式(二):单例模式的5种实现方式,以及在多线程环境下5种创建单例模式的效率
- Java设计模式(二):单例模式的5种实现方式,以及在多线程环境下5种创建单例模式的效率
- 多线程环境下使用的单例模式的实现
- 多线程情况下的单例模式创建
- c++单例模式在多线程环境下的安全性
- java多线程环境下单利模式的实现
- 单例模式如何在多线程环境下保证安全—Double Checked Locking 模式使用
- 单例模式的5种实现方式,以及在多线程环境下5种创建单例模式的效率
- (转载CSDN)序列化:创建可序列化的类
- 多线程下的单例模式如何去写
- SingleTon模式的多线程环境
- 如何创建一个VS2005 VC++下的D3D项目环境
- C++下多线程的创建
- 多线程环境下的计数器
- 设计模式——6.单例模式(包含多线程环境下的一些写法)
- 解决问题能力的关键是什么
- 只能实例化一次的类 (Singleton)
- 统计2 泊松过程 大数定理 正态分布
- qwb与矩阵 简单dp
- 诗意歌词
- 如何创建多线程环境下的可序列化单例模式
- [Leetcode]122. Best Time to Buy and Sell Stock II
- 1. Spring Web MVC框架简介
- Ubuntu: 忘记登陆密码
- python安装错误代码2503/2502
- 【SSH框架初了解】
- 常用控件
- 项目实训——第二周(2)
- ThinkPHP5学习(8)数据库-基本操作