懒汉模式即生成对象实例的时机是在第一次需要该实例时,与饿汉模式相对应
1.基本懒汉式
public class Test_2 implements Serializable {
//懒汉在类加载时并不创建实例对象,而是置为null
private static Test_2 Instance=null;
//私有方法防止外部调用创建对象
private Test_2(){
System.out.println("构造方法");
}
//外部类获得单例对象方法,懒汉是在获取Instance时生成实例对象
public static Test_2 getInstance(){
if (Instance==null)
Instance=new Test_2();
return Instance;
}
//其他方法
public static void otherMethod(){
System.out.println("other");
}
}
此方法实现会有线程安全问题,如果当两个或多个线程同时在getInstance时,若刚刚好都对Instance==null判断成立,在同一时间段进入对象生成代码段,最后每个线程创建不同的实例对象,线程不安全。解决方法如下:在方法上加上锁,这样每个时刻都只能有一个线程来访问这个方法。但是该方法性能并不高,因为我们需要防止的只是在最开始Instance=null时导致的多个线程去创建实例对象。而当度过该时间段后,所有的线程都不会去创建实例对象,也就不需要该锁。从而导致性能低。
public static synchronized Test_2 getInstance(){
if (Instance==null)
Instance=new Test_2();
return Instance;
}
2.DCL双检锁实现懒汉式
由于普通方式性能低,从而有了DCL来对此进行优化,该方法是先判断Instance是否为null,如果为空才会去加锁让线程竞争,如果不为空直接执行完毕。从而提高效率。当加锁后进入的线程首先也会判断一次Instance是否为空,这是为了防止多个线程逃离第一次检查而进入锁的竞争阶段而导致的多个线程创建多个实例对象。
public class Test_2 implements Serializable {
//懒汉在类加载时并不创建实例对象,而是置为null
private static volatile Test_2 Instance=null;
//私有方法防止外部调用创建对象
private Test_2(){
System.out.println("构造方法");
}
//外部类获得单例对象方法,懒汉是在获取Instance时生成实例对象
public static Test_2 getInstance(){
if (Instance==null)
synchronized (Test_2.class){
if (Instance==null){
Instance=new Test_2();
}
}
return Instance;
}
//其他方法
public static void otherMethod(){
System.out.println("other");
}
}
而该方法在Instance前面要加上 volatile关键字,这是为了防止cpu指令流水为了高效率而对指令进行顺序调整而产生的错误。保证指令的按序发射。(当然也不完全一样,只是这个意思,并不是全部按照顺序,而是在某些地方不追求性能而保证安全,该处是对Instance的赋值顺序固定不变)
3.内部类实现懒汉
public class Test_3 {
private Test_3(){}
//静态内部类
private static class Util{
static Test_3 Instance=new Test_3();
}
//得到内部类创建的实例对象
public static Test_3 getInstance(){
return Util.Instance;
}
//其他方法
public static void otherMethod(){
System.out.println("other");
}
}
该方法是线程安全的因为内部类是static的,是jvm保证创建的线程安全,而且当调用其他方法时,并没有触发内部类的加载,从而是懒汉式



