单例模式一:饥饿模式
/**
* 饥饿模式
*
* 不存在并发问题
* @author davidwang2006@aliyun.com
* @date 2020/3/6 0006 下午 9:12
*/
public class EagerSingleton {
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton(){
System.out.printf("%s: construct called....%n",getClass().getSimpleName());
}
public static EagerSingleton getInstance(){
return INSTANCE;
}
public void sing(){
System.out.printf("%s: Sing....%n",getClass().getSimpleName());
}
}
单例模式二:DLC模式
即懒加载模式中的double lock check模式
/**
* double lock check模式
* @author davidwang2006@aliyun.com
* @date 2020/3/6 0006 下午 9:13
*/
public class DoubleLockSingleton {
//必须使用volatile 是因为cpu有可能指令re-order,
//此关键字会插入内存屏障,阻止cpu re-order
private volatile static DoubleLockSingleton INSTANCE = null;
private DoubleLockSingleton(){
System.out.printf("%s: construct called....%n",getClass().getSimpleName());
}
public static DoubleLockSingleton getInstance(){
//double check null
if(INSTANCE == null){
synchronized (DoubleLockSingleton.class){
//must check again
//because maybe another thread initialize it already
if(INSTANCE == null){
INSTANCE = new DoubleLockSingleton();
}
}
}
return INSTANCE;
}
public void sing(){
System.out.printf("%s: Sing....%n",getClass().getSimpleName());
}
}
单例模式三:静态内部类模式
优点:不需要double lock check
/**
* When the singleton class is loaded,
* inner class is not loaded and hence doesn’t create object when loading the class.
* Inner class is created only when getInstance() method is called.
* So it may seem like eager initialization but it is lazy initialization.
* This is the most widely used approach as it doesn’t use synchronization.
* @author davidwang2006@aliyun.com
* @date 2020/3/6 0006 下午 9:16
*/
public class InnerClassSingleton {
private InnerClassSingleton(){
System.out.printf("%s: construct called....%n",getClass().getSimpleName());
}
private static class Holder{
static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
}
public static InnerClassSingleton getInstance(){
return Holder.INSTANCE;
}
public void sing(){
System.out.printf("%s: Sing....%n",getClass().getSimpleName());
}
}
单例模式四:枚举模式
/**
*
* 这一种是最好的
* 比InnerClassSingleton还好一点,因为不用再定义一些不必须的属性和内部类
*
* @author davidwang2006@aliyun.com
* @date 2020/3/6 0006 下午 9:30
*/
public enum EnumSingleton {
INSTANCE;
private EnumSingleton(){
System.out.printf("%s: construct called....%n",getClass().getSimpleName());
}
//etc
private int propertyA;
//etc....
public void sing(){
System.out.printf("%s: Sing....%n",getClass().getSimpleName());
}
}
优劣比较
以前四种写法均不存在并发问题,枚举与饥饿模式写法最简便,个人比较推荐枚举模式。
测试类
/**
* test for singleton
*
* java -verbose:class SingletonBoot
*
* @author davidwang2006@aliyun.com
* @date 2020/3/11 0011 上午 11:22
*/
public class SingletonBoot {
public static void main(String[] args) {
System.out.printf("%nBEGIN%n%n");
EagerSingleton.getInstance().sing();
DoubleLockSingleton.getInstance().sing();
InnerClassSingleton.getInstance().sing();
EnumSingleton.INSTANCE.sing();
System.out.printf("%nEND%n%n");
}
}
执行结果
BEGIN
[Loaded com.david.learning.concurrent.singleton.EagerSingleton]
[Loaded java.util.Formattable from rt.jar]
EagerSingleton: construct called....
EagerSingleton: Sing....
[Loaded com.david.learning.concurrent.singleton.DoubleLockSingleton]
DoubleLockSingleton: construct called....
DoubleLockSingleton: Sing....
[Loaded com.david.learning.concurrent.singleton.InnerClassSingleton]
[Loaded com.david.learning.concurrent.singleton.InnerClassSingleton$Holder]
InnerClassSingleton: construct called....
InnerClassSingleton: Sing....
[Loaded com.david.learning.concurrent.singleton.EnumSingleton]
EnumSingleton: construct called....
EnumSingleton: Sing....
END
澄清
饥饿模式写法与DLC模式相比较并不比DLC耗资源,虽然它是饥饿模式,但其也是在使用这个类的地方才会加载(引用成员或使用方法时初始化)它(变相懒加载)。
如有谬误,请各位网友不吝指教。