java 单例模式容易忽略的细节
java单例模式
直接讲实现单例模式的两种方法:懒汉式和饿汉式,单例模式的概念自己上网搜吧这里就不讲了!
这里会涉及到java中的jvm,如果你没有这方面的知识,我建议你先去补补,不然会有点迷糊!
首先说说类什么时候进行加载?
java虚拟机没有进行强制性的约束,但是对于初始化却严格规定了有且只有4种情况必须先对类进行初始化。
我们要知道的是在类加载的过程中,加载、验证、准备是在初始化之前完成的,所以进行了初始化,加载、验证、准备自然就在之前完成了。
然后这四种情况是分别遇到 new 、 getstatic 、 putstatic 和 invokestatic 这四条指令时,如果对应的类没有初始化,则要对对应的类先进行初始化。
讲完类加载时机,就可以讲懒汉式和饿汉式了。
直接先说说懒汉式为什么是线程不安全的?
先看最开始的代码:
public class Student2 { //1:构造私有 private Student2(){} //2:定义私有静态成员变量,先不初始化 private static Student2 student = null; //3:定义公开静态方法,获取本身对象 public static Student2 getSingletonInstance(){ //没有对象,再去创建 if (student == null) { student = new Student2(); } //有对象就返回已有对象 return student; } }
结合之前讲的类加载内容,遇到new或加载静态方法了就会进行类加载了。
线程1它new了一个对象,线程2它紧接着也new一个对象,第二个对象的值把第一个对象的值覆盖了,不管new了多少个对象,都会产生垃圾对象,只有最后一个对象才会保持住,其他对象都会变成不可达对象,被垃圾回收,这个过程就相当于产生了大量无效对象,这就是线程不安全的原因!
那为了让懒汉式变得线程安全,我们要怎么做?
看代码:
public class Student4 { private volatile static Student4 student = null; private Student4() {} public static Student4 getSingletonInstance() { if (student == null) {//第一个null判断,是先大范围过滤一遍 synchronized (Student4.class) { if (student == null) { student = new Student4(); } } } return student; } }
这个叫双重检查锁DCL,第一个if先大范围判断是不是空值,经过synchronized,线程1先进去执行完后,线程2才能进去,然后第二个if判断是否完成创建类的实例,线程1创建完了,线程2就不用创建了。
那为什么要加volatile关键字呢?
因为我们Student student = new Student()的执行过程是:
1、new触发类加载机制(已经被加载过的类不需要再次加载)
2、分配内存空间
3、将对象进行初始化4、讲对象引用地址赋值给栈空间中的变量但我们JVM中的JIT即时编辑器会对代码的执行过程进行优化,把过程变为1、2、4、3。
这是什么意思呢?就是未经初始化直接赋值,这样就是student直接有值了,但整个对象还未初始化完成,所以这个对象是不完整的,是个未成品。在JVM规范中,它是一个根本不能用的对象。
到了这个时候,线程1做了这么多事,我们让它休息会,给CPU稍微停一下,线程2就来了,它就直接得到了对象,但它调用对象的方法时,就会报错。虽然这个对象有值,但还未初始化完成。所以我们要加上volatile关键字禁止指令重新排序。
面试重灾区说的差不多了,饿汉式还是要讲讲。
最后就说说饿汉式为什么没有线程安全问题?
看代码:
public class Student1 { // 2:成员变量初始化本身对象 private static Student1 student = new Student1(); // 构造私有 private Student1() { } // 3:对外提供公共方法获取对象 public static Student1 getSingletonInstance() { return student; } public void sayHello(String name) { System.out.println("hello," + name); } }
根据类加载的东西,在多线程的条件下,线程1先执行getSingletonInstance()时,就会进行类加载,类的静态资源就会进行初始化。根据JVM安全机制里说的,当一个类被JVM加载的时候,该类的加载是线程安全的,相当于JVM对该过程加锁了。所以整个过程处于一个锁的范围内,然后静态成员变量进行初始化就相当于Student1()被new了,只会被new一次。
当第二个线程进来,它就发现这个类已经被加载了,就不需要进行加载了,对象也不需要频繁创建,所以线程是安全的!
总结
老刘看过很多关于java单例模式的资料,多多少少都会缺少一点细节,这次老刘把它补全了。
最后,如果觉得有哪里写的不好或者有错误的地方,可以联系公众号:努力的老刘,进行交流。
如果觉得写的不错,给老刘点个赞!
以上就是java 单例模式容易忽略的细节的详细内容,更多关于java 单例模式的资料请关注猪先飞其它相关文章!
相关文章
- 这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 神马是“解释器模式”?先翻开《GOF》看看Definition:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。在开篇之前还是要科普几个概念: 抽象语法树: 解释器模式并未解释如...2014-06-07
- 这篇文章主要为大家介绍了JavaScript设计模式中的装饰者模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-21
- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15- 这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03
Java 8 Stream 的终极技巧——Collectors 功能与操作方法详解
这篇文章主要介绍了Java 8 Stream Collectors 功能与操作方法,结合实例形式详细分析了Java 8 Stream Collectors 功能、操作方法及相关注意事项,需要的朋友可以参考下...2020-05-20- 这篇文章主要介绍了Java List集合返回值去掉中括号('[ ]')的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-29
Java中lombok的@Builder注解的解析与简单使用详解
这篇文章主要介绍了Java中lombok的@Builder注解的解析与简单使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-06- 下面小编就为大家带来一篇java中String类型变量的赋值问题介绍。小编觉得挺不错的。现在分享给大家,给大家一个参考。...2016-03-28