最完美的单例模式
Posted 再等三分钟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最完美的单例模式相关的知识,希望对你有一定的参考价值。
在工作中用最常用的选择是饿汉式和双重检查懒汉式。最完美的是Effective Java中推荐的enum方式
1、恶汉式:
类加载到内存中,就实例化一个单例,JVM保证线程安全,简单实用
一个小缺点:无论用到与否,类加载时就完成实例化
public class HungrySingleton {
private static final HungrySingleton INSTANCE = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return INSTANCE;
}
2、懒汉式
一个是在静态方法上加锁,相当于锁定了整个类,可能会对效率有影响
public class LazySingleton1 {
private static LazySingleton1 INSTANCE;
private LazySingleton1() {
}
/**
* 1、静态方法加锁,锁定了LazySingleton
*
* @return
*/
public static synchronized LazySingleton1 getInstance1() {
if (INSTANCE == null) {
INSTANCE = new LazySingleton1();
}
return INSTANCE;
}
双重检查机制:要加volatile,防止JVM的指令重排
public class LazySingleton2 {
private static volatile LazySingleton2 INSTANCE;
/**
* 2、此方法不行,
* 当一个线程A执行到if时,暂停,另一个线程B进来,判断为空,则new,A接着执行会再次创建,所以出现了二次加锁
*
* @return
*/
public static synchronized LazySingleton2 getInstance1() {
if (INSTANCE == null) {
synchronized (LazySingleton2.class) {
INSTANCE = new LazySingleton2();
}
}
return INSTANCE;
}
/**
* 3、双重检查
* 要加volatile,防止JVM的指令重排
*
* @return
*/
public static synchronized LazySingleton2 getInstance() {
if (INSTANCE == null) {
synchronized (LazySingleton2.class) {
if (INSTANCE == null) {
INSTANCE = new LazySingleton2();
}
}
}
return INSTANCE;
}
}
3、通过静态内部类实现: 在LazySingleton加载时,内部静态类LazyHolder是不会被加载的,在getInstance时才会new,相当于实现了懒加载。线程安全是由JVM保证的,JVM在加载时,一个类只会加载一次,所以不会出现并发问题。
public class LazySingleton3 {
private static class LazyHolder {
private final static LazySingleton3 LAZY_SINGLETON = new LazySingleton3();
}
public static LazySingleton3 getInstance4() {
return LazyHolder.LAZY_SINGLETON;
}
4、通过枚举实现单例:
枚举单例:Effective Java中推荐这么写, 不仅可以解决线程同步,还可以防止反序列化(枚举类没有构造方法)
public enum PerfectLazySingleton {
INTANCE;
}
在工作中基本饿汉式就可以了,有些人可能为了炫技,证明我懂锁,所以使用双重锁,也可以使用枚举单例,这种会对不知道的人有些奇怪。
以上是关于最完美的单例模式的主要内容,如果未能解决你的问题,请参考以下文章