主要思想
单例模式属于常见设计模式中的一种,且应用较多,它主要是使一个类的实例数量保持一个,主要实现的思想为:将该类的构造方法设为私有,外部无法直接使用该类的构造函数进行实例化这个类的对象。外部类只能使用该类提供的静态方法创建该类的实例对象。在该静态方法中,通过对该类的实例对象进行存在性判断,若已经存在则直接返回该实例对象,若不存在,则通过调用私有构造函数进行创建后并返回。它具有多种实现方式。
常见写法1:饿汉式
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
这种为较为常见的一种写法,其中遵循将构造函数设置为私有方法。并且将唯一一个实例对象设置为静态常变量类型。这种方式,使得该类的唯一一个实例对象在类装载的时候就完成了实例化。这样可以避免多线程同步的问题,缺点则是没有实现懒加载(lacy loading),如果该类的实例一直没有使用到,则实例化的对象造成内存浪费。
常见写法2:懒汉式
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
这种方式最大的问题就是线程不安全,无法在多线程的情况下使用。但该中方式起到了一定的lazy loading的效果,如果是单线程环境下,还是可以使用。
线程同步优化懒汉式
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
由于最初版本的懒汉式线程不安全,这里使用同步方法的方式保证线程安全。但这种方式的问题是执行效率太低。
同步方式两次检查
public class Singleton {
private static volatile Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singletion.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
这种方式与上述同步方式的不同在于,在getInstance方法中进行了两次的check instance是否为null,第一重的check,保证了在多线程的情况下,当第一个线程同步的方式使用getInstance时已经创建了INSATNCE的实例,然后当第二个线程调用getInstance方法时,依然可以直接返回INSTANCE实例,同时保证了线程安全。
推荐使用:静态内部类
public class Singleton {
private Singleton() {}
static class SingletonInstance {
private final static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
该方式与第一种饿汉式的方式相类似,对INSTANCE的限制都是使用静态常变量的方式。但与第一种方式不同的是,第一种方式的静态常变量在类加载的时候就完成了实例化。而这种方式,通过将静态常变量放置到一个静态内部类中,保证了不会再外部类状态时进行对象实例化,从而只有在调用getInstance方法时才会进行对象的实例化,保证了lazy loading的机制。同时静态内部类的设置保证了线程安全和高效率。因此推荐使用。