由单例模式的优化,引出的java线程数据同步和类加载顺序知识点总结
摘要
几种单例模式的优缺点及其改进优化
DCL失效问题的原因以及解决
java中线程同步关键字final和volatile
java内存屏障
java类加载顺序总结
饿汉单例
//片段1
class Singleton1{
private static Singleton1 instance = new Singleton1();
private Singleton1(){}
public static Singleton1 getInstance(){
return instance;
}
}
- 是线程安全的
- 在加载类时就已经对单例进行了初始化,不能做到使用时再进行资源初始化。需要考虑单例对象资源消耗方面的问题和资源加载的时机
- 不建议使用
懒汉单例
//片段2
class Singleton2{
private static Singleton2 instance;
private Singleton2(){}
public static Singleton2 getInstance(){
if(instance == null)
instance = new Singleton2();
return instance;
}
}
//片段3
class Singleton3{
private static Singleton3 instance;
private Singleton3(){}
private synchronized static Singleton3 getInstance(){
if(instance == null)
instance = new Singleton3();
return instance;
}
}
- 在首次调用时才会进行资源的初始化,一定程度上节省了资源
- 片段2是非线程安全的,片段3是线程安全的,但是每次获取单例时都会进行同步,造成不必要的同步开销,效率不高
- 不建议使用
DCL(double check lock) 单例
//片段4
class Singleton4{
private static Singleton4 instance;
private Singleton4(){}
private static Singleton4 getInstance(){
if(instance == null){
synchronized(Singleton4.class){
if(instance == null)
instance = new Singleton4();
}
}
return instance;
}
}
- 保证只在第一次调用时初始化单例资源,资源利用率高
- 是线程安全的
- 在jdk1.5之前,高并发情况下可能会遇到DCL失效的情况
“双重检查”,线程th1和线程th2同时调用getInstance()
方法,此时Singleton4
未被实例化,th1和th2进入到第一个if判断中,th1率先获取到了同步锁进入到同步代码块中,th2等待获取该类的同步锁,之后Singleton4
正常实例化后,th1释放同步锁,获取到单例对象,th2此时获取到了同步锁进入同步代码块中,此时第二个if能够保证不会继续进行资源初始化,保证单例的唯一性。