四种单例写法与测试

Posted muche-moqi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四种单例写法与测试相关的知识,希望对你有一定的参考价值。

四种单例写法与测试

本文主要实现了四种方式的单例模式与测试,双重检测代码稍微麻烦点。每一个类都设有一个测试方法,可以替换自己需要做的一些业务。

各种方式需要注意的点

  1. 饿汉式
    • 私有化构造函数
    • final定义instance
  2. 双重检测
    • 私有化构造函数
    • volatile修饰instance,否则会可能得到未初始化的实例
    • 可替换为其他非静态实例使用
  3. 静态内部类
    • 私有化构造函数
    • 只能静态实例
  4. 枚举
    • 不用构造函数
    • 可定义多个枚举,如:enum{ IN1, INS2 }则实现多例
    • 保证线程安全,唯一不会被反射和序列化影响的单例模式

参考:
你知道吗?枚举单例模式是世界上最好的单例模式
《java 并发编程的艺术》
《effective java》

以下是代码:

import java.util.concurrent.atomic.AtomicLong;


public class Singleton {
    public static void main(String[] args) {
        //测试饿汉式
        HungrySingleton h1 = HungrySingleton.getInstance();
        HungrySingleton h2 = HungrySingleton.getInstance();
        System.out.println("两个实例是否相等:" + (h1 == h2));
        System.out.println("第一次加" + h1.getId());
        System.out.println("第二次加" + h2.getId());

        System.out.println("------------------------------------");
        //测试双重检测
        DoubleCheckSingleton d1 = DoubleCheckSingleton.getInstance();
        DoubleCheckSingleton d2 = DoubleCheckSingleton.getInstance();
        System.out.println("两个实例是否相等:" + (d1 == d2));
        System.out.println("第一次加" + d1.getId());
        System.out.println("第二次加" + d2.getId());

        System.out.println("------------------------------------");
        //测试静态内部类
        StatiInnerClassSingleton s1 = StatiInnerClassSingleton.getInstance();
        StatiInnerClassSingleton s2 = StatiInnerClassSingleton.getInstance();
        System.out.println("两个实例是否相等:" + (s1 == s2));
        System.out.println("第一次加" + s1.getId());
        System.out.println("第二次加" + s2.getId());

        System.out.println("------------------------------------");
        //测试枚举
        EnumSingleton e1 = EnumSingleton.INSTANCE;
        EnumSingleton e2 = EnumSingleton.INSTANCE;
        System.out.println("两个实例是否相等:" + (e1 == e2));
        System.out.println("第一次加" + e1.getId());
        System.out.println("第二次加" + e2.getId());
    }

}

/**
 * 饿汉式
 */
class HungrySingleton{
    private static final HungrySingleton instance = new HungrySingleton();
    private HungrySingleton(){}

    public static HungrySingleton getInstance(){
        return instance;
    }

    //用于测试单例正确性
    private AtomicLong id = new AtomicLong(0);
    public long getId() {
        return id.incrementAndGet();
    }
}

/**
 * 双重检测
 */
class DoubleCheckSingleton{
    private static volatile DoubleCheckSingleton instance = null;
    private DoubleCheckSingleton(){}

    public static DoubleCheckSingleton getInstance(){
        if(instance == null){
            synchronized (DoubleCheckSingleton.class){
                if(instance == null){
                    instance = new DoubleCheckSingleton();
                }
            }
        }
        return instance;
    }

    //用于测试单例正确性
    private AtomicLong id = new AtomicLong(0);
    public long getId() {
        return id.incrementAndGet();
    }
}


/**
 * 静态内部类
 */
class StatiInnerClassSingleton{
    private StatiInnerClassSingleton(){}

    private static class InstanceHolder{
        public static StatiInnerClassSingleton instance = new StatiInnerClassSingleton();
    }

    public static StatiInnerClassSingleton getInstance(){
        return InstanceHolder.instance;
    }

    //用于测试单例正确性
    private AtomicLong id = new AtomicLong(0);
    public long getId() {
        return id.incrementAndGet();
    }
}


/**
 * 枚举
 */
enum EnumSingleton{
    INSTANCE;

    //用于测试单例正确性
    private AtomicLong id = new AtomicLong(0);
    public long getId() {
        return id.incrementAndGet();
    }
}



以上是关于四种单例写法与测试的主要内容,如果未能解决你的问题,请参考以下文章

两种单例模式的写法

四种单例模式

Egret中的三种单例写法

使用单例时的三种单例写法

常见的几种单例模式写法

8种单例模式写法助你搞定面试