单例模式

单例模式应该算是我们经常遇到的一种模式,比如说线程池就是应用了单例,Spring bean也是运用了单例,单例模式节省了整个系统内存的开销。下面代码基于线程安全的前提下。
1、饿汉式。类加载时就生成了相应的对象。

public class Singleton1 {

    private static Singleton1 instance = new Singleton1();

    private Singleton1(){}

    public static Singleton1 getInstance(){
        return instance;
    }

}

2、懒汉式。在第一次调用方法时才生成对象。

public class Singleton2 {

    private static Singleton2 instance;

    private Singleton2(){}

    public static synchronized Singleton2 getInstance(){
        if(instance == null){
            instance = new Singleton2();
        }
        return instance;
    }

}

3、双重检查式。两次判断,将同步放到方法内部,但是由于java内存模型,这个可能会出现问题。

public class Singleton3 {

    private static Singleton3 instance;

    private Singleton3(){}

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

}

4、静态内部类。延迟加载,天然的线程安全。

public class Singleton4 {

    private static final class InstanceClass{
        private static Singleton4 instance = new Singleton4();
    }

    private Singleton4(){
        if(InstanceClass.instance != null){
            throw new RuntimeException();
        }
    }

    public static Singleton4 getInstance(){
        return InstanceClass.instance;
    }

}

5、枚举式。jvm保证其线程安全性,效率也高。

public enum Singleton5 {

    INSTANCE;
    public void getInstance(){}

}

上面一共是五种单例的形式,每一种都有其对应的特点。总的来说,如果想要延迟加载,最好选用静态内部类,如果不需要,枚举较好。下面是对这五种模式创建对象效率的一个模拟测试,分别调用几种模式每次生成10万个对象。这里采用了countDownLatch类作为多线程环境下的计数器,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。

public class SingleTest {

    public static void main(String[] args) throws Exception {
        Long startTime = System.currentTimeMillis();
        int ThreadNum = 10;
        final CountDownLatch countDownLatch = new CountDownLatch(ThreadNum);
        for (int i = 0; i < ThreadNum; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000000; j++) {
                    Singleton1 s = Singleton1.getInstance();
                    //Singleton5 s = Singleton5.INSTANCE;
                }
                countDownLatch.countDown();
            }).start();

        }
        countDownLatch.await();
        Long endTime  =System.currentTimeMillis();
        System.out.println("耗时为:" + (endTime - startTime));
    }

}

最后运行发现,除了懒汉式生成效率较低之外,其他几种模式差距都很小。

发布了56 篇原创文章 · 获赞 23 · 访问量 5万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章