《剑指offer》笔记
设计一个类,我们只能生成该类的一个实例。
1、不好的解法:只适合单线程环境:将构造函数设为私有函数禁止他人创建实例
/**
* 单例模式,懒汉式,线程不安全
*/
public static class Singleton2 {
private static Singleton2 instance = null;
private Singleton2() {
}
public static Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
在单线程中工作正常,在多线程下(如果同时运行到判断instance是否为null语句时,若instance的确没有创建,那么两个线程会创建两个实例)
2、不好的解法:在多线程中能工作但效率不高
/**
* 单例模式,懒汉式,线程安全,多线程环境下效率不高
*/
public static class Singleton3 {
private static Singleton3 instance = null;
private Singleton3() {
}
public static synchronized Singleton3 getInstance() {
if (instance == null) {
instance = new Singleton3();
}
return instance;
}
}
加同步锁是一个非常耗时的操作,在没有必要的情况下尽量避免。
3、可行的解法:加同步锁前后两次判断实例是否已存在
对解法二改进,在实例创建之前加锁,实例已经创建之后,不需要加锁
/**
* 静态内部类,使用双重校验锁,线程安全【推荐】
*/
public static class Singleton7 {
private volatile static Singleton7 instance = null;
private Singleton7() {
}
public static Singleton7 getInstance() {
if (instance == null) {
synchronized (Singleton7.class) {
if (instance == null) {
instance = new Singleton7();
}
}
}
return instance;
}
}
两次判断instance,避免违背单一性。提高了效率,但是实现复杂。
4、强推荐做法:利用静态构造函数
/**
* * 单例模式,饿汉式,线程安全
*/
public static class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
在初始化静态变量INSTANCE时创建了一个实例,运行时能保证只调用一次静态构造函数,就可以保证只初始化一次instance.
5、强推方法:实现按需创建实例
解决方法4中创建实例过早的问题。
/**
* 单例模式,使用静态内部类,线程安全【推荐】
*/
public static class Singleton5 {
private final static class SingletonHolder {
private static final Singleton5 INSTANCE = new Singleton5();
}
private Singleton5() {
}
public static Singleton5 getInstance() {
return SingletonHolder.INSTANCE;
}
}
只有在运行到SingletonHolder.INSTANCE时得到Singleton5的实例,会自动调用SingletonHolder的静态构造函数创建实例INSTANCE。可以做到真正需要的时候创建实例,提高空间使用效率。