内容简介:推荐理由:为什么要使用volatile修饰?虽然已经使用synchronized进行同步,但在第4步创建对象时,会有下面的伪代码:
public class Singleton {
private volatile static Singleton singleton; //1:volatile修饰
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) { //2:减少不要同步,优化性能
synchronized (Singleton.class) { // 3:同步,线程安全
if (singleton == null) {
singleton = new Singleton(); //4:创建singleton 对象
}
}
}
return singleton;
}
}
复制代码
推荐理由:
- 延迟初始化。和懒汉模式一致,只有在初次调用静态方法
getSingleton,才会初始化signleton实例。 - 性能优化。同步会造成性能下降,在同步前通过判读`singleton是否初始化,减少不必要的同步开销。
- 线程安全。同步创建Singleton对象,同时注意到静态变量
singleton使用volatile修饰。
为什么要使用volatile修饰?
虽然已经使用synchronized进行同步,但在第4步创建对象时,会有下面的伪代码:
memory=allocate(); //1:分配内存空间 ctorInstance(); //2:初始化对象 singleton=memory; //3:设置singleton指向刚 排序 的内存空间 复制代码
当线程A在执行上面伪代码时,2和3可能会发生重排序,因为重排序并不影响运行结果,还可以提升性能,所以JVM是允许的。如果此时伪代码发生重排序,步骤变为1->3->2,线程A执行到第3步时,线程B调用 getsingleton 方法,在判断 singleton==null 时不为 null ,则返回 singleton 。但此时 singleton 并还没初始化完毕,线程B访问的将是个还没初始化完毕的对象。 当声明对象的引用为volatile后,伪代码的2、3的重排序在多线程中将被禁止!
静态内部类模式
public class Singleton {
private Singleton(){
}
public static Singleton getSingleton(){
return Inner.instance;
}
private static class Inner {
private static final Singleton instance = new Singleton();
}
}
复制代码
推荐理由:
- 实现代码简洁。和双重检查单例对比,静态内部类单例实现代码真的是太简洁,又清晰明了。
- 延迟初始化。调用
getSingleton才初始化Singleton对象。 - 线程安全。JVM在执行类的初始化阶段,会获得一个可以同步多个线程对同一个类的初始化的锁。
如何实现线程安全?
线程A和线程B同时试图获得Singleton对象的初始化锁,假设线程A获取到了,那么线程B一直等待初始化锁。线程A执行类初始化,就算双重检查模式中伪代码发生了重排序,也不会影响线程A的初始化结果。初始化完后,释放锁。线程B获得初始化锁,发现Singleton对象已经初始化完毕,释放锁,不进行初始化,获得Singleton对象。
在涉及到反射和序列化的单例中,建议使用下文的枚举类型模式。
其他类型的单例模式
懒汉模式(多线程不安全)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
复制代码
饿汉单例模式(多线程不安全)
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
复制代码
懒汉单例模式和饿汉单例模式都可以通过变种,实现线程安全。
枚举单例模式(多线程安全)
public enum Singleton {
INSTANCE;
public void doSomething(){
//todo doSomething
}
}
复制代码
在Joshua Bloch大神的《Effective Java》是推荐该方法的。虽然线程安全,在实际开发中,还没有被广泛采用。因为太过简洁以致于可读性较差,还没有在实战中被广泛推广。枚举单例模式的线程安全同样利用静态内部类中讲到类初始化锁。枚举单例模式能够在序列化和反射中保证实例的唯一性。
高手之间的过招,必选择枚举单例模式。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 为什么我强烈推荐你用枚举来实现单例模式
- 分析:基于文本内容推荐和协同过滤推荐
- 《文章推荐系统》系列之推荐流程设计
- 只推荐一本 JavaScript 书,你推荐哪本?
- 推荐策略产品经理:什么是协同过滤推荐算法?
- 推荐系统评价:什么是好的推荐系统
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
TCP/IP详解 卷1:协议
W.Richard Stevens / 范建华 / 机械工业出版社 / 2000-4-1 / 45.00元
《TCP/IP详解卷1:协议》是一本完整而详细的TCP/IP协议指南。描述了属于每一层的各个协议以及它们如何在不同操作系统中运行。作者W.Richard Stevens用Lawrence Berkeley实验室的tcpdump程序来捕获不同操作系统和TCP/IP实现之间传输的不同分组。对tcpdump输出的研究可以帮助理解不同协议如何工作。 《TCP/IP详解卷1:协议》适合作为计算机专业学......一起来看看 《TCP/IP详解 卷1:协议》 这本书的介绍吧!
XML 在线格式化
在线 XML 格式化压缩工具
html转js在线工具
html转js在线工具