说道DoubleCheck(双重检查锁),就要从懒汉单例模式说起。
为了解决懒汉模式出现多例的情况,我们最容易想到的就是使用synchronized关键字。
看下面代码:
public class Myobject{
private static Myobject myobject;
private Myobject(){}
synchronized public static Myobject getInstance(){
try{
if(myobject!=null){
}else{
Thread.sleep(3000);
myobject = new Myobject();
}
}catch(InterruptedException e){
e.printStackTrace();
}
return myobject;
}
}
使用上面的同步方法可以实现单例模式,但是这种方法的运行效率非常低,下一个线程想要得到对象,必须等到上一个线程释放锁以后,才可以继续执行。
为了解决上面的问题,可以使用同步代码块,减小同步的颗粒度。
看下面代码:
public class Myobject{
private static Myobject myobject;
private Myobject(){}
public static Myobject getInstance(){
try{
synchronized(Myobject.class){
if(myobject!=null){
}else{
Thread.sleep(3000);
myobject = new Myobject();
}
}
}catch(InterruptedException e){
e.printStackTrace();
}
return myObject;
}
}
此方法使用同步语句块,只对实例化对象的关键代码进行同步,但是同步颗粒度也很大。所以我们可以只对关键代码进行同步。
看下面的例子:
public class Myobject{
private static Myobject myobject;
private Myobject(){}
public static Myobject getInstance(){
try{
if(myobject!=null){
}else{
Thread.sleep(3000);
synchronized(Myobject.class){
myobject = new Myobject();
}
}
}catch(InterruptedException e){
e.printStackTrace();
}
return myObject;
}
}
上面的方法同步颗粒度确实很小,但是无法实现单例,那我们证明一下:
public class MyThread extends Thread{
public void run(){
System.out.println(Myobject.getInstance().hashcode());
}
}
public class run{
public static void main(String[] args){
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start();
t2.start();
t3.start();
}
}
运行结果:
7214088
15020296
16130931
那么如何才能解决上面的问题呢,这时候就要用到DoubleCheck机制了(差点儿就忘了这篇博文讲的啥了。。。。)
看下面代码:
public class Myobject{
private static Myobject myobject;
private Myobject(){}
public static Myobject getInstance(){
try{
if(myobject!=null){
}else{
Thread.sleep(3000);
synchronized(Myobject.class){
if(myobject==null)
myobject = new Myobject();
}
}
}catch(InterruptedException e){
e.printStackTrace();
}
return myObject;
}
}