张佳ZHJ·且行且珍惜-实用破解软件资源教程

JAVA单列模式9种写法

10 11月
作者:zhangjiajia105@gmail.com|分类:实用教程

1.饿汉式(静态常量) 推荐指数:★★☆☆☆ 优点:不会有线程安全问题。 缺点:在类加载的时候就创建对象,如一直没使用到该对象的话,就造成了内存浪费,如对象初始化的工作很多也会影响性能。2.饿汉式(静态代码块) 推荐指数:★★☆☆☆ 优缺点和第一种方式基本一致。3.懒汉式(线程不安全) 推荐指数:★☆☆☆☆ 优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。 缺点:有线程安全问题。4.懒汉式改造(线程安全) 推荐指数:★★☆☆☆ 优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。 缺点:没有线程安全问题,但是有很大的性能问题,当多个线程同时到达getInstance()方法时,需要排队进入。5.懒汉式改造(线程不安全) 推荐指数:☆☆☆☆☆ 优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。 缺点:线程不安全,还有性能问题!多个线程在synchronized那一行排队,进入代码块后一样会创建多个对象。 6.双重检查缺陷版(线程不安全) 推荐指数:☆☆☆☆☆ 优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。 缺点:线程不安全,这里的线程不安全要涉及到对象的创建过程和指令重排序。 详细讨论:

这个优化我们利用了双重检测机制和同步锁,这种方式也称为双重同步锁单例模式,但是这个案例还是线程不安全的,大家通过代码层面的分析后,发现确实不会有线程安全问题,那问题出现在哪呢?这个其实要和对象创建步骤和Jvm指令重排挂钩,我们正常创建对象的指令步骤是这样的:

memory = allocate() 分配对象的内存空间 ctorInstance() 初始化对象 instance = memory 设置instance指向刚分配的内存 但是因为JVM和cpu优化,发生了指令重排,

memory = allocate() 分配对象的内存空间 instance = memory 设置instance指向刚分配的内存 ctorInstance() 初始化对象 我们可以结合代码,假如A线程进入同步代码块执行instance = new Singleton6(),执行到“instance = memory 设置instance指向刚分配的内存”,这个时候B线程在第一次执行“if (instance == null)”,发现instance不为空,直接返回instance实例,其实线程B得到的这个实例并没有完全初始化(A还没有执行完对象的初始化步骤)就已经使用了。

关于对象创建过程可以参考 Java对象的创建、内存布局和访问定位

那如何禁止指令重排呢,很简单,用我们前面文提到的volatile关键字就可以了

7.双重检查优化版(线程安全) 推荐指数:★★★★☆ 优点:使用到的时候才会创建对象,不会造成各种资源浪费问题。 缺点:复杂。 8.静态内部类方式 推荐指数:★★★☆☆ 优点:使用到的时候才会创建对象,不会造成各种资源浪费问题,线程安全。 缺点:没有太大缺点。 9.枚举单例 推荐指数:★★★★★ 优点:使用到的时候才会创建对象,不会造成各种资源浪费问题,线程安全。 缺点:最优方案。

浏览1647 评论0
返回
目录
返回
首页
up路人A-让农民赔付700万,带粉丝以每单26元买4500斤水果,并鼓动投诉店家欺骗不发货,除了些还有一些薅羊毛严重可能导致违法犯罪 JAVA动态调试技术原理及实践