6.1立即加载与延迟加载
MyObject.java
public class MyObject {
private static MyObject myObject = new MyObject();
private MyObject(){}
public static MyObject getInstance(){
//该方法未同步
return myObject;
}
}
MyThread.java
public class MyThread extends Thread{
@Override
public void run(){
System.out.println(MyObject.getInstance().hashCode());
}
}
Run.java
public class Run {
public static void main(String[] args) {
MyThread A = new MyThread();
MyThread B = new MyThread();
MyThread C = new MyThread();
A.start();
B.start();
C.start();
}
}
执行结果
468440919
468440919
468440919
三个线程获得的对象的 hash 值一样,说明是同一个对象。
修改 MyObjec.java
public class MyObject {
private static MyObject myObject ;
private MyObject(){}
public static MyObject getInstance(){
//该方法未同步
if (myObject == null)myObject = new MyObject();
return myObject;
}
}
运行结果
496361680
1990702044
1990702044
因为 getInstance() 没有加锁同步,所以会有生成多个实例的情况,违背了单例模式。
为getInstance() 加 synchronized,同步内容过多,对总体效率不利
修改 MyObject.java,加上 synchronized
public class MyObject {
private static MyObject myObject ;
private MyObject(){}
synchronized public static MyObject getInstance(){
//已同步
if (myObject == null)myObject = new MyObject();
return myObject;
}
}
使用同步块,仍然会有不同步,可能产生多个实例而违背单例模式
修改 MyObject.java,添加同步块。
public class MyObject {
private static MyObject myObject ;
private MyObject(){}
public static MyObject getInstance(){
try{
if(myObject == null){
Thread.sleep(2000);//模拟对象属性配置耗时
synchronized (MyObject.class){
myObject = new MyObject();
}
}
}catch (InterruptedException e){
}
return myObject;
}
}
DCL 双检查锁机制,完全解决
修改 MyObject.java,两次检查 MyObject 是否为 null。
public class MyObject {
private static MyObject myObject ;
private MyObject(){}
public static MyObject getInstance(){
try{
if(myObject == null){
Thread.sleep(2000);//模拟对象属性配置耗时
synchronized (MyObject.class){
if (myObject == null){
myObject = new MyObject();
}
}
}
}catch (InterruptedException e){
}
return myObject;
}
}