lazy loaded thread-safe单例模式实现
DCL (double checked locking 实现法) double checked locking ,顾名思义,就是双检查法,检查实例INSTANCE是否为null或者已经实例化了。
public class DoubleCheckedLockingSingleton {
private volatile DoubleCheckedLockingSingleton INSTANCE;// 创建一个私有的,可变的 实例
//volatile:能保证在一个线程中改变这个值,其他线程能够立即知道发生改变。
public DoubleCheckedLockingSingleton getInstance() {
if (INSTANCE == null) {
synchronized (DoubleCheckedLockingSingleton.class) {
if (INSTANCE == null)
INSTANCE = new DoubleCheckedLockingSingleton();
}
}
return INSTANCE;
}
}
注:synchronized(this)与synchronized(ClassName.class)区别
- synchronized(this)对当前对象是同步的,所以只有一个线程可以访问每个实例,但不同的线程可以访问不同的实例。
例如,你有很多线程和很多该类实例,但是同时每个实例对应的同步内容都可以被一个线程访问。(在任意时间点,这个类的一个实例只能被一个线程访问,但一个线程可以同时访问该类多个实例) - synchronized(ClassName.class)对当前对象的类(或其他类)是同步的,所以只有一个线程可以访问该类的实例。
例如,你有很多线程和很多该类实例,但是同时只允许一个线程访问一个实例的同步内容。(在任意时间点,该类的所有实例只能有一个实例被所有线程中的一个线程访问)
lazy initialization holder class 模式实现法
package 单例模式;
public class Singleton {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
*/
private static class SingletonHolder {
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static Singleton instance = new Singleton();
}
/**
* 私有化构造方法
*/
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
当getInstance方法第一次被调用的时候,它第一次读取SingletonHolder.instance,导致SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会被虚拟机在装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。
注:关于延迟初始化(lazy loaded)
“除非绝对必要,否则就不要延迟初始化”。延迟初始化是一把双刃剑,它降低了初始化类或者创建实例的开销,却增加了访问被延迟初始化的域的开销,考虑到延迟初始化的域最终需要初始化的开销以及域的访问开销,延迟初始化实际上降低了性能。
静态工厂实现法
public class Singleton {
private static final Singleton INSTATNCE = new Singleton();
private Singleton() {
}
public static Singleton getSingleton() {
return INSTATNCE;
}
}
static关键字:在加载类的过程中完成变量的内存分配
final关键字:描述变量为常量,不会被改变
在类加载时就将INSTATNCE 创建好,在程序中调用的都是已经创建好的实例。