5种单例模式
- 饿汉式(2种)
- 懒汉式(3种)
- 双重检测
- 静态内部类
- 枚举
饿汉式
- 静态常量
class SingletonDemo{
private static final SingletonDemo instance = new SingletonDemo();
private SingletonDemo{}
public static SingletonDemo getInstance(){
return instance;
}
}
- 静态代码块
class SingletonDemo{
private static SingletonDemo instance;
static{
instance = new SingletonDemo();
}
private SingletonDemo{}
public static SingletonDemo getInstance(){
return instance;
}
}
优缺点:
优点:类加载时instance实例就被装载进内存,而类装载是一个线程安全的过程,static变量和static代码块只会被装载一次,所以饿汉式能够保证线程安全
缺点:不管应用最终有没有用到这个单例,该单例都会被装载到内存中。这就有可能会造成内存浪费。
懒汉式
- 没有加锁
class SingletonDemo{
private static SingletonDemo instance;
private SingletonDemo{}
public static SingletonDemo getInstance(){
if(instance == null){
instance = new SingletonDemo();
}
return instance;
}
}
优点:开启懒加载模式,只有在需要用到该单例的时候才将该实例装载到内存,避免了内存的浪费
缺点:无法保证线程安全性,因为没有对实例化唯一单例的代码加锁,所以多线程编程下根本无法保证线程安全性,结果有可能创建了好几个实例
2. 使用同步方法
class SingletonDemo{
private volatile static SingletonDemo instance;
private SingletonDemo{}
public static synchronized SingletonDemo getInstance(){
if(instance == null){
instance = new SingletonDemo();
}
return instance;
}
}
优点:在方法上加锁可以保证线程安全
缺点:并发执行效率太低,单例只需要在第一次实例化时保证线程安全性即可,后续只需要获取该唯一实例就行,此时不需要加锁,此时加锁会影响到线程的并发性。
- 使用同步代码块
class SingletonDemo{
private volatile static SingletonDemo instance;
private SingletonDemo{}
public static SingletonDemo getInstance(){
if(instance == null){
synchronized{
instance = new SingletonDemo();
}
}
return instance;
}
}
缺点:该写法无法保证线程安全
双重检测
class SingletonDemo{
private volatile static SingletonDemo instance;
private SingletonDemo{}
public static SingletonDemo getInstance(){
if(instance == null){
synchronized{
if(instance == null){
instance = new SingletonDemo();
}
}
}
return instance;
}
}
优点:既有懒加载的特性,又保证了线程安全性,推荐使用该方式创建单例
静态内部类
class SingletonDemo{
static class Interior{
private static final SingletonDemo instance = new SingletonDemo();
}
private SingletonDemo{}
public static SingletonDemo getInstance(){
return Interior.instance;
}
}
优点:利用内部静态类在SingletonDemo初始化时并未将Interior类装载到内存中,所以并不会造成内存浪费。当调用getInstance方法时才将instance装载到内存中,而将类装载到内存这个过程是线程安全的,所以线程安全性也得以保障。推荐使用此种方式创建单例
枚举
enum SingletonDemo{
INSTANCE;
void doSomething(){
...
}
}
//获取单例的时候
SingletonDemo.INSTANCE
优点:既有懒加载的特性,又有线程安全性,除此之外最大的优点是可以防止反射和反序列化对单例的破坏
关于枚举单例以及反射和序列化对单例的破坏的具体内容可以参考以下两篇博客
设计模式之单例模式七(使用枚举类的最佳实践)
解析——为什么单元素的枚举类型是单例模式的最佳实现