单例分为恶汉模式和懒汉模式
1、恶汉模式,代码:
public class SingletonHungry {
private static SingletonHungryobj =new SingletonHungry();
//将构造方法私有化,防止外部使用构造方法进行创建实例
private SingletonHungry() {
}
public static SingletonHungrygetInstance(){
return obj;
}
}
2、懒汉模式,代码:
public class SingletonLazy {
private static volatile SingletonLazyobj;
private SingletonLazy(){
//防止外界使用构造方法创建实例
}
/**
* 问题:多线程并发时,可能会创建多个obj对象
* @return
*/
public static SingletonLazygetInstance1(){
if(obj ==null){
obj =new SingletonLazy();
}
return obj;
}
/**
*@description: 问题:当线程a执行到mark1时,线程b执行到synchronized块内,此时obj为null
* 线程b会创建一个obj对象,同时线程a由于进入if代码块时以为obj为null,所以也将创建一个对象
* 此时会创建多个obj对象
*/
public static SingletonLazygetInstance2(){
if(obj ==null){
//mark1
synchronized (SingletonLazy.class) {
obj =new SingletonLazy();
}
}
return obj;
}
/**
* 也有问题:多线程时,当a线程进入synchronized代码块时,由于obj = new SingletonLazy()会分三步进行
* 1、obj分配内存空间地址
* 2、创建SingletonLazy.class对象的实例
* 3、将步骤2创建的实例对象指向步骤1的内存空间地址
* 由于步骤1的时候obj已经!=null了,此时b线程进入则直接返回obj对象,此时obj还没有创建完成。
* 解决办法是在obj对象前加一个修饰符volatile,此处用到了volatile的防止指令重排的功能
* @return
*/
public static SingletonLazygetInstance3(){
if(obj ==null){
synchronized (SingletonLazy.class) {
if(obj ==null) {
obj =new SingletonLazy();
}
}
}
return obj;
}
}
注:
1、指令重排的含义:对于非原子性的操作,在不影响最终结果的情况下,其拆分成的原子操作可能会被重新排列执行顺序,以提高计算机的执行效率。
2、volatile禁止指令重排,用volatile修饰后的obj,对它的写操作就会添加一个内存屏障,在写操作完成之前不会有其他的读操作。
3、volatile多线程可见性的原理:(lock)写操作时锁住主内存;其他读操作必须在写操作完成后执行;嗅探机制使其它的栈缓存失效;