一、为什么需要单例模式?
可以保证一个类仅有一个实例,控制实例数目,节约系统的资源。比如:数据库的连接池。一些资源管理器常被设计成单例模式
二、怎么使用
2.1 饿汉式
是否多线程安全:是
是否 Lazy 初始化:否
描述:
优点:没有加锁,执行效率提高
缺点:在某些情况下,不是因为调用getInstance而导致的类初始化的话,那么会存在浪费内存的情况
该模式是基于classLoader机制避免多线程的问题,当读取类的静态字段(类静态常量不是)、调用类的静态方法时(当然还有很多情况会触发类的初始化,更多细节参考深入理解JVM虚拟机)。会触发类的初始化。当进行初始化时,JVM会为类的静态语句块和为类变量赋值操作,生成<clinit>的汇编指令,该指令保证只有一个线程运行。会阻塞其他线程,因此能保证只初始化一次。
备注:有人说在类加载时就会初始化,浪费内存,个人感觉是不对的。首先JVM的类加载会进行类的加载(加载class文件),验证(验证字节码文件),准备(为类变量分配内存并赋初值),解析(将符号引号转为直接引用);紧接着再初始化,但是需要注意的是,已经说明JVM什么时候才会为类进行初始化。所以,说类在加载时就会初始化,个人感觉是不对的。如果个人讲述错误,请留言
代码示例:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
2.2、静态内部类
是否多线程安全:是
是否 Lazy 初始化:是
代码示例:
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
2.3、双检锁/双重检验锁(DCL,double checked locking)
是否多线程安全:是
是否 Lazy 初始化:是
描述:
缺点:实现复杂,且效率过低,每次都需要判断一次if。不推荐使用
请注意
如果singleton变量没有加上volatile,那么就是非线程安全的。来模拟一下:
线程A走到④处,初始化完毕了singleton,线程B走到②处。因为没有加volatile,所以此时singleton可能不会对其他内存立即可见,所以线程B也走到了④,因此,实例化了2个对象。
代码示例:
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) { ①
synchronized (Singleton.class) { ②
if (singleton == null) { ③
singleton = new Singleton(); ④
}
}
}
return singleton;
}
}
2.4、枚举
是否多线程安全:是
是否 Lazy 初始化:是
描述:推荐使用
对于枚举类来说,每个对象(INSTANCE)都是被public static final修饰的。其次构造函数默认私有。所以用来实现单例模式,是非常适合的。
在Effective Java第二版的第77条,推荐使用枚举实现单例模式。
代码示例:
public enum Test{
INSTANCE;
private Singleton singleton;
Test() {
singleton = new Singleton;
}
public Singleton getInstance() {
return singleton;
}
}
有关参考:
java并发编程实战
EffectiveJava 第二版
http://www.runoob.com/design-...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。