单例模式

背景:单例模式模式是在编程中常常使用,他能够对须要使用的资金进行一次性初始化,防止屡次初始化屡次资源释放带来性能的开销。编程

最近在读《JAVA并发编程的艺术》发现有些知识点不错,整理出来。缓存

单例模式经常使用模式是懒汉模式和饿汉模式多线程

懒汉模式:就是用到时候才new出来。并发

饿汉模式:类一开始就加载好,可直接使用。性能

 

单线程状况下,咱们会经过如下实现才生成一个懒汉模式的单例模式类。可是多线程访问时候,这种实现不知足要求。优化

public class Singleton {
    public static Singleton instance = null;

    public Singleton() {
        //todo
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

上面实现,若是在多线程状况下,可能出现多个线程同时访问instance == null 出现问题。接下来,介绍几种能够避免多线程竞争访问致使的问题。spa

(一)同步处理,延迟初始化,任什么时候刻只有一个线程抢占到访问资源。线程

public class Singleton {
    public static Singleton instance = null;

    public Singleton() {
        //todo
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

可是这个方法也是弊端,因为采用同步处理,synchronized致使性能开销。若是getInstance()被多个线程频繁调用,会致使程序执行性能降低。反之,若是getInstance()不被多个线程频繁调用,那么这个延迟初始化将是不错的选择。code

(二)双重检查锁,优化方案一出现多线程频繁调用instance(instance!=null)时阻塞的问题。对象

public class Singleton {
    public static Singleton instance = null;

    public Singleton() {
        //todo
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

优势:若是instance不为null, 多线程访问instance就不会出现阻塞,提升了性能,减小了开销。

缺点:因为JAVA内存模型,不一样JIT编译器之间出现重排序问题,可能会出现线程A执行instance时instance==null,因而进入instance = new Singleton(), 线程B发现instance != null,可是这个instance可能未初始化。接下来我来细化下JMM执行过程方便理解。

instance = new Singleton() 能够分解成如下几步:

1. memory = allocate(); 分配对象的内存空间

2. ctorInstance(memory); 初始化对象

3. instance = memory; 设置instance指向刚分配的内存地址

因为在为伪代码中2和3之间可能会出现重排序. 引入《JAVA并发编程的艺术》的图。懒得本身画了。

鉴于这个问题,咱们能够有以下更佳解决方式,把instance定义为volatile。JDK5以后引入volatile关键字,解决各个编译器处理器缓存和总线内存之间数据一致性问题。当把对象声明为volatile后,2和3重排序问题的问题,在多进程中被禁止,即不容许重排序。

public class Singleton {
    public static volatile Singleton instance = null;

    public Singleton() {
        //todo
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

(三)若是你使用Spring来管理bean, @Autowired注释自己就是单例模式,一开始就生成好一个bean实例,即为饿汉模式。

@Component
public class Singleton {
    
    @Autowired
    public Singleton(....){
        //TODO
    }
}
相关文章
相关标签/搜索