标签:turn 进入 代码块 on() 多线程 另一个 ble ssi desc
一.
单例模式指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。
二.饿汉模式
public class HungrySingleton {
private HungrySingleton(){}
private final static HungrySingleton HUNGRY_SINGLETON ;
static {
HUNGRY_SINGLETON = new HungrySingleton();
}
public static HungrySingleton getInstance(){
return HUNGRY_SINGLETON;
}
}
饿汉式是指类的被加载的时候,就被初始化,并创建单例对象,不会存在访问安全问题。
缺点:所有的饿汉单例对象都会在项目启动时初始化,会造成大量内存资源浪费。
三.懒汉模式
(1)考虑到饿汉模式的缺点后,加以修改,在类被调用的时候,才初始化。
public class LazySimpleSingleton {
private LazySimpleSingleton(){}
private static LazySimpleSingleton LAZY_SIMPLE_SINGLETON = null;
public static LazySimpleSingleton getIn,stance(){
if(null==LAZY_SIMPLE_SINGLETON){
LAZY_SIMPLE_SINGLETON = new LazySimpleSingleton();
return LAZY_SIMPLE_SINGLETON;
}
return LAZY_SIMPLE_SINGLETON;
}
}
但是会带来一个新的问题,就是在多线程环境下,有两个线程同一时间进入getInstance方法,同事满足null=LAZY_SIMPLE_SINGLETON时,会创建两个对象,然后后创建的会覆盖先创建的单例对象。
考虑到这个问题后,进一步优化,使用synchronized关键字,给方法加锁。
public class LazySimpleSingleton {
private LazySimpleSingleton(){}
private static LazySimpleSingleton LAZY_SIMPLE_SINGLETON = null;
public synchronized static LazySimpleSingleton getInstance(){
if(null==LAZY_SIMPLE_SINGLETON){
LAZY_SIMPLE_SINGLETON = new LazySimpleSingleton();
return LAZY_SIMPLE_SINGLETON;
}
return LAZY_SIMPLE_SINGLETON;
}
}
当一个线程调用getInstance方法时,另一个线程也调用该方法,会出现阻塞,直到第一个线程执行结束,才继续调用,完美解决了线程安全问题。
出现新的问题:
如果线程数量暴增,给getInstatnce加锁,只有一个线程运行该方法,其他线程全部阻塞等待,用户体验不好。新的解决方案--双重检查锁单例写法应运而生。
(2)双重检查锁单例 (进门安检一次,闸口再检查一次)
改造一下写法:
public class LazyDoubleSingleton {
private volatile static LazyDoubleSingleton instance;
private LazyDoubleSingleton(){}
public static LazyDoubleSingleton getInstance(){
synchronized (LazyDoubleSingleton.class){
if(null==instance){
instance = new LazyDoubleSingleton();
}
}
return instance;
}
}
这样的写法,其实和上一种写法差不多,都会造成大量线程阻塞。那如果把if条件往上升一级呢,先判断,再加锁。
public class LazyDoubleSingleton {
private volatile static LazyDoubleSingleton instance;
private LazyDoubleSingleton(){}
public static LazyDoubleSingleton getInstance(){
if(null==instance){
synchronized (LazyDoubleSingleton.class){
instance = new LazyDoubleSingleton();
}
}
return instance;
}
}
经过此次修改后,还是会出现线程安全问题。
因为当两个线程同事满足null==instance条件后,会执行sychronized代码块的代码,该对象还是会被创建两次。
再优化一下,我们在sychronized代码块中再进行对象的非空检查,这样该对象就不会被创建两次。
public class LazyDoubleSingleton {
private volatile static LazyDoubleSingleton instance;
private LazyDoubleSingleton(){}
public static LazyDoubleSingleton getInstance(){
//检查是否要阻塞
if(null==instance){
synchronized (LazyDoubleSingleton.class){
//检查是否要创建对象
if(null==instance){
instance = new LazyDoubleSingleton();
}
}
}
return instance;
}
}
四.静态内部类单例的写法
双重检查锁单例这种方式虽然解决了线程安全问题和性能问题,但是用到了sychronized总是要上锁,对性能还是有一些影响。我们可以采用静态内部类的方式进行优化。
/**
* @Author wen.jie
* @Description 使用InnerClassSingleton类时,会默认先初始化内部类,如果没有使用,则内部类不初始化
**/
public class InnerClassSingleton {
private InnerClassSingleton(){}
public static InnerClassSingleton getInstance(){
return InnerClass.INNER_CLASS_SINGLETON;
}
private static class InnerClass{
private static final InnerClassSingleton INNER_CLASS_SINGLETON = new InnerClassSingleton();
}
}
这种方式兼顾了饿汉单例写法的内存浪费问题和sychronized的性能问题,内部类一定要在方法调用之前就被初始化,巧妙的避开了线程安全问题。静态内部类单例写法真的完美了吗?(未完待续)
标签:turn 进入 代码块 on() 多线程 另一个 ble ssi desc
原文地址:https://www.cnblogs.com/wwjj4811/p/13581741.html