单例模式,用来保证一个对象只能创建一个实例,同时,它还提供了对实例的全局访问方法。
单例模式的实现非常简单,只由单个类组成。为了确保单例实例的唯一性,所有的单例构造器都要被声明为私有的(private),再通过声明静态(static)方法实现全局访问获得该单例实例。
普通代码实现:
public class Singleton{
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void doSomething() {}
}
//使用单例对象时,只需进行调用,代码如下
Singleton.getInstance().doSomething();
双重校验锁机制的同步锁单例模式代码实现:
public class Singleton{
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
public void doSomething() {}
上述代码保证了同步锁(locking)只有在实例没被创建的情况下才起作用,如果单例实例已经被创建了,那么任何线程都能用非同步的方式获取当前的实例。
注意到instance == null条件被检查了两次,因为我们需要保证在synchronized代码块中也要进行一次检查。
静态内部类单例模式:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程,这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。
无锁的线程安全单例模式代码实现
public class LockFreeSingleton{
private static final LockFreeSingleton instance = new LockFreeSingleton();
private LockFreeSingleton() {}
public static synchronized LockFreeSingleton getInstance() {
return instance;
}
public void doSomething() {}
}
类只会被加载一次,上述代码通过在声明时直接实例化静态成员的方式来保证一个类只有一个实例。