专注Java教育14年 全国咨询/投诉热线:444-1124-454
赢咖4LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 三种懒汉式单例模式

三种懒汉式单例模式

更新时间:2022-12-26 17:25:52 来源:赢咖4 浏览276次

懒汉式单例模式,是在程序需要用到该实例时才会创建的。这样就不会像饿汉式一样,在类加载过程中就会创建。这样就减少了内存的浪费,当然也自然而然的带来了一些缺点:需要时才创建,影响程序的执行效率。另外,懒汉式单例模式在使用时进行创建,势必会带来线程安全的问题,需要解决以上问题,就需要用到锁。锁的使用也在一定程度上会带来一定的执行效率问题。

第一种:普通的懒汉式单例模式

直接上代码:

public class LazySingleton {
    private LazySingleton() {
    }

    private volatile static LazySingleton instance;

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

这种设计明显的一个问题就是执行效率低,无论是否已经存在实例,在多线程的情况下都会发生阻塞。

对以上代码进行改进,首先让当程序中实例存在的时候,直接返回实例,不需要抢占锁。当程序中不存在实例时,再抢占锁进行创建。根据以上的思想,出现了第二种懒汉式方式:

第二种:双重判断型单例模式

public class LazyDoubleCheckSingleton {
    private LazyDoubleCheckSingleton() {
    }

    private volatile static LazyDoubleCheckSingleton instance;

    public static LazyDoubleCheckSingleton getInstance() {
        //确定是否需要阻塞
        if (instance == null) {
            synchronized (LazyDoubleCheckSingleton.class) {
                //确定是否需要创建实例
                if (instance == null) {
                    //这里在多线程的情况下会出现指令重排的问题,所以对共有资源instance使用关键字volatile修饰
                    instance = new LazyDoubleCheckSingleton();
                }
            }
        }
        return instance;
    }

}

对于第二种方式,较第一种方式而言,性能提高了。但是代码的可读性差了。

第三种:利用java语法本身特性

public class LazyStaicSingleton {
    private LazyStaicSingleton(){}

    public static LazyStaicSingleton getInstance(){
        return Hander.INSTANCE;
    }

    private static class Hander{
        private static final LazyStaicSingleton INSTANCE=new LazyStaicSingleton();
    }
}

针对以上三种方式,都可以通过反射破坏其单例模式的特性,这个时候可以在私有构造方法种如下设计:

  private LazyStaicSingleton(){
        if(Hander.INSTANCE!=null){
            throw new RuntimeException("不允许非法访问");
        }
    }

这样在通过反射创建实例时就会报错。

测试代码如下:

public class LazyStaticSingletonTest {
    public static void main(String[] args) {
        //先创建一个实例
        LazyStaicSingleton instance=LazyStaicSingleton.getInstance();
        System.out.println(instance);
        //通过反射创建实例
        try{
            Class<?> clazz=LazyStaicSingleton.class;
            Constructor c = clazz.getDeclaredConstructor(null);
            c.setAccessible(true);
            Object lazyStaicSingleton=c.newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

结果:

java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at com.example.singleton.LazyStaticSingletonTest.main(LazyStaticSingletonTest.java:17)
Caused by: java.lang.RuntimeException: 不允许非法访问
	at com.example.singleton.lazy.LazyStaicSingleton.<init>(LazyStaicSingleton.java:6)
	... 5 more

以上就是赢咖4小编介绍的"三种懒汉式单例模式",希望对大家有帮助,如有疑问,请在线咨询,有专业老师随时为您务。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>