首先给出代码:
//基于类初始化的线程安全的单例
class SingleTon4{
private SingleTon4(){}
private static class InnerClass{
private static SingleTon4 instance= new SingleTon4();
}
public static SingleTon4 getInstance(){//如果没有到这里,那么不会加载上面的内部类
return InnerClass.instance; //这里将导致InstanceHolder类被初始化
}
}
静态内部类的优点是:外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。具体来说当SingleTon第一次被加载时,并不需要去加载SingleTonHoler,只有当getInstance()方法第一次被调用时,使用INSTANCE的时候,才会导致虚拟机加载SingleTonHoler类。这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
那么他是如何实现线程安全的?
首先要了解类加载过程中的最后一个阶段:即类的初始化,类的初始化阶本质就是执行类构造器的<clinit>方法。
<clinit>方法:这不是由程序员写的程序,而是根据代码由javac编译器生成的。它是由类里面所有的类变量的赋值动作和静态代码块组成的。JVM内部会保证一个类的<clinit>方法在多线程环境下被正确的加锁同步,也就是说如果多个线程同时去进行“类的初始化”,那么只有一个线程会去执行类的<clinit>方法,其他的线