关于Java单例的理解

单例模式很简单但是你都懂了吗?

Posted by 晓晨DEV on December 21, 2016

毕业那年找工作,在学校面试的时候,有一个题目是让我写个单例,当时心想这玩意不是手到擒来分分钟写了2个,不知不觉工作了2年再回头看这个最简单的单例模式,还是有很多东西的,网上多数讲解并没有讲清楚。

1.饿汉单例

最简单的单例,私有化构造方法,提供一个get方法,内部搞一个实例。 我是线程安全的,但是我没有实现懒加载!

public class Singleton {
    private static Singleton INSTANCE = new Singleton();

    private Singleton(){
        
    }

    public static Singleton getInstance(){
        return INSTANCE;
    }
}

2.懒汉单例

第一种单例不管这个实例是否用到都初始化了一个,显然没必要,用到的时候再初始化。 我也是线程不安全的哦!

public class Singleton {
   public static Singleton getInstance(){
        if(INSTANCE == null){
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}

3.加锁单例

以上两种单例都是线程不安全的,想要线程安全,加个锁搞定啦; 我是线程安全的哦

public class Singleton {
    private static Singleton INSTANCE;

    private Singleton(){}

    public static synchronized Singleton getInstance(){
        if(INSTANCE == null){
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}

4.双层锁检测单例

对于第三种写法的单例,其实只要初始化的时候加上锁就可以了,但是直接加到方法上就会导致每次访问单例都是带锁的,于是就有了双层锁检测单例。

我是线程安全的哦

这种单例双层锁不少人知道的,但是 volatile 这个关键字没有加上,那就没有意义了,初始化时分为实例化和赋值两步,但是Java虚拟机不能保证在其他线程中这两步骤的顺序,加上 volatile 这个关键字就能保证实例化和赋值是有序的,简单说,在另一个线程眼中,只要这个INSTANCE为null初始化就没完成,只要完成了INSTANCE就不为null,我看到不少双层锁单例没加这个关键字,那就没意义了。


public class Singleton {
    private static volatile Singleton INSTANCE;

    private Singleton(){}

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

5.静态内部类单例

我是线程安全的哦

其实我们的单例就想保证线程安全和懒加载,如下这种静态内部类写法我解释一下: 首先加载 Singleton 的时候并没加载Holder,懒加载已经实现了。 然后对于线程安全,在第一次掉 getInstance 的时候虚拟机发现 Holder 没有初始化,那就初始化Holder,而虚拟机会保证类加载正常完成所以类加载是线程安全的,相当于把线程安全的事情由虚拟机保证了。

public class Singleton {

    private static class Holder{
        private static Singleton INSTANCE = new Singleton();
    }

    private Singleton(){}

    public static Singleton getInstance(){
        return Holder.INSTANCE;
    }
}

以上是对单例模式的总结。


分享