在平常的编程中,有一些对象我们只需要一个,比如:线程池、缓存、日志对象,对于这类对象,我们只需要它在全局中存在一份,如果存在多份,就会发生不可预知的问题。这个时候,单例模式就可以非常好的解决这类问题。
单例模式主要分为两种,懒汉式和饿汉式。
正如其名一样,懒汉式就是程序比较懒,一开始不初始化好对象(类加载时就未初始化),等我需要的时候,我才去初始化它。
而饿汉式呢,则是这个对象急需使用,一开始就初始化好了(类加载时就完成了初始化),等我要用的时候直接用就行了。
如上图懒汉式,在单线程的情况下,这样是没有问题的,但是在多线程情况下,2个线程同时进入 判空语句,就会产生2个不同的对象,这样就会产生线程安全的问题,最直接的方法就是加锁。
但是加锁存在一个问题,就是对整个方法都加了锁,会造成方法效率的大幅度下降,大概会下降100倍,如果你的程序对效率要求不高的话,可以用这个,对效率要求比较高的话,则有一种更适合的模式,"双重检查加锁":
volatile 关键字用于保证对象被初始化时,多个线程能正确的处理obj变量,它是如何能保证obj变量能够被正确的处理呢?
主要是在volatile修饰的对象读写加上内存屏障,volatile的写对所有的线程第一时间可见,获取的单例对象不会是没有初始化完的对象,这样使用才不会出问题。第一次判断对象不等于空时才进入,如果对象被创建了,就不用再进入同步代码块当中,synchronized关键字只会被执行一次,第二次判断是进入区块后,再检查一次,对象为空才会创建对象。