单例模式的定义:确保某一个类只有一个实例,而且这个类可以自行实例化,并向整个系统提供这个实例。
最最简单的方法(饿汉模式):
public class Singleton {
private static final Singleton singleton = new Singleton();
// 通过将构造函数私有化,限制产生多个对象
private Singleton() {
}
// 通过该方法获取实例对象
public static Singleton getSingleton() {
return singleton;
}
// 类中的其它方法尽量是static
public static void doSomething() {
}
}
最最简单的方法(懒汉模式):线程不安全
问题:
1. 如果一个线程A执行到singleton = new Singleton(),但是还没获取对象,第二个线程B也在执行,执行到(singleton == null)判断,那么线程B判断为真,于是继续执行,那么就会导致在内存中出现两个重复的对象。
2. 如果有N多个线程,每次执行到对象赋值操作的时候时间片就到了,那么就会有很多线程都判断singleton为null,所以产生好多对象实例,从而导致sinleton被多次赋值,最后return的时候也会返回不同的地址的实例对象。
解决办法:使用Synchronized对方法进行加锁
public class Singleton {
private static Singleton singleton = null;
// 限制产生多个对象
private Singleton() {
}
// 通过该方法获取实例对象
public static Singleton getSingleton() {
if(singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
优化后的单例模式(对整个代码块进行加锁):
优点:简单粗暴,直接给把整个方法加锁
缺点:锁粒度太大,导致效率过低
public class Singleton {
private static Singleton singleton = null;
// 限制产生多个对象
private Singleton() {
}
// 通过该方法获取实例对象
public static synchronized Singleton getSingleton() {
if(singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
再次优化,只对创建对象的部分进行加锁:
那么问题又来了,看波浪线那里,如果多个线程都跑到波浪线那里了,在每个线程拿到锁之后还是会进行多次赋值,所以还需要再优化,。
public class Singleton {
private static Singleton singleton = null;
// 限制产生多个对象
private Singleton() {
}
// 通过该方法获取实例对象
public static Singleton getSingleton() {
if(singleton == null) {
---------------------------------------------
synchronized(Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
}
再优化:
改进点:再加一层判空。当一个线程拿到锁,再释放锁,那么对象必定已经实例化,其它线程再拿到锁的时候也必须再次判空,再判空的时候就发现变量已经被赋值,所以就退出返回
新问题:
再new一个对象的时候,会走以下过程,但是这三条指令也许会乱序执行,正常是123,乱序执行是132,因此如果线程A执行完13,时间片就到了,那么线程B进来发现变量已经不为空,所以就会返回一个没有进行第二步,即未进行初始化操作的对象,最后导致出错。
1.给SingletonLazy5的实例分配内存。
2.初始化SingletonLazy5的构造器
3.将singletonLazy对象指向分配的内存空间(注意到这步instance就非null了)。
public class Singleton {
private static Singleton singleton = null;
// 限制产生多个对象
private Singleton() {
}
// 通过该方法获取实例对象
public static Singleton getSingleton() {
if(singleton == null) {
synchronized(Singleton.class) {
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
终极方案:使用volatile防止重排序
public class Singleton {
private static volatile Singleton singleton = null;
// 限制产生多个对象
private Singleton() {
}
// 通过该方法获取实例对象
public static Singleton getSingleton() {
if(singleton == null) {
synchronized(Singleton.class) {
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}