设计模式之单例模式

一、饿汉式
饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间。相关代码如下:

//饿汉式
class Demo1{
    //1-私有化构造方法
    private Demo1(){
        System.out.println("创建了一个Demo1对象");
    }
    //2-提供唯一实例对象
    private static final Demo1 instance = new Demo1();

    public static Demo1 getInstance(){
        return instance;
    }
}
//测试用例
public class Test002_Singleton {
    public static void main(String[] args) {
        for(int i = 0; i < 10; i++){
            new Thread(()->{
                Demo1.getInstance();
            }).start();
        }
    }
}

执行结果:
在这里插入图片描述
上图可知只创建了一次Demo1实例对象,由此可见,10个线程获取的是同一个实例对象。
二、懒汉式
懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间。相关代码如下:

//懒汉式
class Demo2{
    //1-私有化构造方法
    private Demo2(){
        System.out.println("创建了一个Demo2对象");
    }
    private static Demo2 instance = null;

    public synchronized static Demo2 getInstance(){
        if(instance == null)
            instance = new Demo2();
        return  instance;
    }
}
//测试用例
public class Test002_Singleton {
    public static void main(String[] args) {
        for(int i = 0; i < 10; i++){
            new Thread(()->{
                Demo2.getInstance();
            }).start();
        }
    }
}

三、静态内部类
静态内部类版本的单例模式利用了jvm的类加载机制,如下代码,jvm的类加载机制保证了Demo3类只能new一次,在加载Demo3的时候不会加载Holder,所以Holder类并没有创建,只有当调用getInstance()方法的时候才会加载Holder类才创建了对象,这个对象就是第一次调用getInstance()方法是创建的,规避了饿汉式的浪费空间的问题因为类加载只进行一次,,所以这个代码既规避了饿汉式的缺点,也规避了懒汉式的缺点。相关代码如下:

//静态内部类
class Demo3{

    //1-私有化构造方法
    private Demo3(){
        System.out.println("创建了一个Demo3对象");
    }
    private static class Holder{
        public static final Demo3 instance = new Demo3();
    }
    public static Demo3 getInstance(){
        return Holder.instance;
    }
}
//测试用例
public class Test002_Singleton {
    public static void main(String[] args) {
        for(int i = 0; i < 10; i++){
            new Thread(()->{
                Demo3.getInstance();
            }).start();
        }
    }
}

四、DCL版本单例模式
为了解决synchronized性能开销大的问题,我们考虑使用先判断对象是否已经被初始化,再决定要不要加锁,像这样先判断对象是否已经被初始化,再决定要不要加锁然后再进行判断,这种方式就是DCL(Double Check Lock双重检查锁),但是这种机制不一定线程安全,原因是有指令重排的存在,加入volatile可以禁止指令重排,这样就实现了高并发模式下的单例模式,相关代码如下:

class Demo4 {

    private Demo4() {
        System.out.println("创建了一个Demo4对象");
    }
    private static volatile Demo4 instance = null;

    //DCL(Double Check Lock双端验锁机制)
    public static Demo4 getInstance() {

        if (instance == null) {

            synchronized (Demo4.class) {

                if (instance == null) {
                    instance = new Demo4();
                    return instance;
                }
            }
        }
        return instance;
    }
}
//测试用例
public class Test002_Singleton {
    public static void main(String[] args) {
        for(int i = 0; i < 10; i++){
            new Thread(()->{
                Demo4.getInstance();
            }).start();
        }
    }
}

你可能感兴趣的:(设计模式,java,jvm)