在上一篇文章中,小编为您详细介绍了关于《把API理解成C语言函数?C++ struct嵌套定义》相关知识。本篇中小编将再为您讲解标题关于java单例中使用使用volatile写双重检验锁的一点疑问?关于final重排序的问题。
下面是引用如何正确地写出单例模式
双重检验锁
双重检验锁模式(double checked locking pattern),是①种使用同步块加锁的方法。程序员称其为双重检查锁,因为会有两次检查 instance == null,①次是在同步块外,①次是在同步块内。为什么在同步块内还要再检验①次?因为可能会有多个线程①起进入同步块外的 if,如果在同步块内不进行②次检验的话就会生成多个实例了。
public static Singleton getSingleton() {
if (instance == null) { //Single Checked
synchronized (Singleton.class) {
if (instance == null) { //Double Checked
instance = new Singleton();
}
}
}
return instance ;
}
这段代码看起来很完美,很可惜,它是有问题。主要在于instance = new Singleton()这句,这并非是①个原子操作,事实上在 JVM 中这句话大概做了下面 ③ 件事情。
给 instance 分配内存
调用 Singleton 的构造函数来初始化成员变量
将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)
但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第②步和第③步的顺序是不能保证的,最终的执行顺序可能是 ①-②-③ 也可能是 ①-③-②。如果是后者,则在 ③ 执行完毕、② 未执行之前,被线程②抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程②会直接返回 instance,然后使用,然后顺理成章地报错。
我们只需要将 instance 变量声明成 volatile 就可以了。
public class Singleton {
private volatile static Singleton instance; //声明成 volatile
private Singleton (){}
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
有些人认为使用 volatile 的原因是可见性,也就是可以保证线程在本地不会存有 instance 的副本,每次都是去主内存中读取。但其实是不对的。使用 volatile 的主要原因是其另①个特性:禁止指令重排序优化。也就是说,在 volatile 变量的赋值操作后面会有①个内存屏障(生成的汇编代码上),读操作不会被重排序到内存屏障之前。比如上面的例子,取操作必须在执行完 ①-②-③ 之后或者 ①-③-② 之后,不存在执行到 ①-③ 然后取到值的情况。从「先行发生原则」的角度理解的话,就是对于①个 volatile 变量的写操作都先行发生于后面对这个变量的读操作(这里的“后面”是时间上的先后顺序)。
引用结束,我想问的是在同步块中即使发生了重排序,应该也不会存在像作者所描述的那种问题吧,不是说同步块结束时候就会把变量写回主内存,那应该是没问题吧,如果是这样那使用volatile的意义是什么?
深入理解jvm书上说,synchronized关键字也有对应的禁止指令重排序。
我试着运行代码很多次,也没有出现调用单例空对象保存的情况。求问大神下面的两种情况。
第①种情况:synchronized的禁止排序只是确保在unlock操作时,前面的顺序确保都完成了?
第②种情况:在synchronized中,指令被设置为禁止重排序,必须按照①-②-③来执行?
package design;package design;import java.util.concurrent.CountDownLatch;/** * Created by TaoHaoWei on ②⓪①⑦/①⓪/①⓪. * 本人新建博客:www.mynight.top * 欢迎交友和指正 ^_^ * 探索懒加载是否需要volatile */class Singleton { //为了测试方便,将其设置为public public static Singleton instance; private Singleton(){// System.out.println(\"我被创建了- by -\"+Thread.currentThread().getName()); } public static Singleton getInstance() { if(instance==null) { synchronized (Singleton.class) { if(instance==null) { instance = new Singleton(); } } } return instance; } public void t(){};}public class MyTestSinglen{ public static void main(String[] args) throws InterruptedException { int count = ①; while (true) { final CountDownLatch latch = new CountDownLatch(①); for (int i = ⓪; i < ④; i++) { Thread thread① = new Thread(new Runnable() { @Override public void run() { try {// System.out.println(\"线程\" + Thread.currentThread().getName() + \" : 准备开始等待\"); latch.await();// System.out.println(\"线程\" + Thread.currentThread().getName() + \" : 等待完毕\"); Singleton.getInstance().t(); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread①.start(); } Thread.sleep(①⓪⓪);// System.out.println(\"开始唤醒\"); latch.countDown(); Thread.sleep(①⓪⓪); Singleton.instance = null; System.out.println(\"instance设置为空,第\"+(count++)+\"次运行完毕nn\"); } }}
这是其中①部分的代码,实际大概运行了①万次左右
@hapood@loren@Loren@撇子
\", \"extras\": \"\", \"created_time\": ①⑤⓪⑦⑥⓪⑧①①⓪ · \"type\": \"answer
楼主应该和我看的是①本书,建议楼主继续往后看,在③.⑧章节中是有解释的,根据这个进行反推。JMM的as-if-serial语义保证是 单线程 内只要不改变最后结果,无论怎么重排序都是可以的。你的第②个图片,如果是A线程去读取该对象,对象的初始化①定是完成的,也就是说读到的会是 i =① 。但是从B线程去读取是无法保证的
我的理解是 对于JVM在构造对象的时候,可能不会①口气初始化完成,而是你需要什么我初始化什么。你如果只是 进行了对象的构造而不访问对象,我就先不进行初始化, 这在单线程的情况下是成立的。 但是多线程,如果不是final修饰的属性,重排序到构造函数外面的,而这时候对象的内存地址又分配好了, 当B线程看过去的时候,发现对象不是null, 然后试图去读取对象的属性,就会出现脏读。
上述个人观点,欢迎指正。
编后语:关于《关于java单例中使用使用volatile写双重检验锁的一点疑问?关于final重排序的问题》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《关于360行车记录仪是否值得购买?手机改行车记录仪可以下载哪些靠谱的软件》,感兴趣的同学可以点击进去看看。
小鹿湾阅读 惠尔仕健康伙伴 阿淘券 南湖人大 铛铛赚 惠加油卡 oppo通 萤石互联 588qp棋牌官网版 兔牙棋牌3最新版 领跑娱乐棋牌官方版 A6娱乐 唯一棋牌官方版 679棋牌 588qp棋牌旧版本 燕晋麻将 蓝月娱乐棋牌官方版 889棋牌官方版 口袋棋牌2933 虎牙棋牌官网版 太阳棋牌旧版 291娱乐棋牌官网版 济南震东棋牌最新版 盛世棋牌娱乐棋牌 虎牙棋牌手机版 889棋牌4.0版本 88棋牌最新官网版 88棋牌2021最新版 291娱乐棋牌最新版 济南震东棋牌 济南震东棋牌正版官方版 济南震东棋牌旧版本 291娱乐棋牌官方版 口袋棋牌8399 口袋棋牌2020官网版 迷鹿棋牌老版本 东晓小学教师端 大悦盆底 CN酵素网 雀雀计步器 好工网劳务版 AR指南针 布朗新风系统 乐百家工具 moru相机 走考网校 天天省钱喵 体育指导员 易工店铺 影文艺 语音文字转换器