Java 仅当线程实际已挂起时才进入同步块的代码是双重检查锁定的示例吗?

Java 仅当线程实际已挂起时才进入同步块的代码是双重检查锁定的示例吗?,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,如果我没记错的话,Java线程中存在一个称为双重检查锁定的Sin 已经有一段时间了,但这有点像检查一个值,然后如果它是真的,进入同步的块并再次检查它。因为已经很久了,我不记得为什么会这样。我记得它与Java规范有关,Java规范允许实现以某种方式对各种语句的执行进行重新排序(因为大多数语句通常不起作用)。 (它的优点是最大限度地减少了进入同步的块的速度。) 我在看: 遇到了: 可以使用一个简单的技巧来删除我们已经完成的同步 添加到“运行循环”的每个迭代中 被一段稍微复杂一点的代码替换 仅当线程实

如果我没记错的话,Java线程中存在一个称为双重检查锁定的Sin

已经有一段时间了,但这有点像检查一个值,然后如果它是
真的
,进入
同步的
块并再次检查它。因为已经很久了,我不记得为什么会这样。我记得它与Java规范有关,Java规范允许实现以某种方式对各种语句的执行进行重新排序(因为大多数语句通常不起作用)。 (它的优点是最大限度地减少了进入
同步的
块的速度。)

我在看: 遇到了:

可以使用一个简单的技巧来删除我们已经完成的同步 添加到“运行循环”的每个迭代中 被一段稍微复杂一点的代码替换 仅当线程实际已被同步时,才输入同步块 暂停:

        if (threadSuspended) {
            synchronized(this) {
                while (threadSuspended)
                    wait();
            }
        }
这感觉有点像双重检查锁定,但我觉得impprob错了,因为它来自官方文档

另外,它是一个
循环的事实似乎有点不对劲。

那么这是邪恶的代码吗?是否?

threadSuspended
变量上使用
volatile
关键字将为您提供所需的效果。问题是,当多个线程访问同一个变量时,可能存在该变量的线程本地缓存。
volatile
关键字确保不会发生这种缓存

这是一篇进一步解释的帖子

编辑:

关于while,由于代码的目的是等待线程不再挂起,因此我认为没有理由不使用
while


此外,如注释中所述,您粘贴的代码段下面的一行提到了
volatile
,完整的代码段下面的几行将
threadSuspended
声明为
volatile boolean

关于双重检查锁定的两个参考:

  • Java并发实践,16.2.4。双重检查锁定
  • 有效Java,第二版,第71项:明智地使用惰性初始化

否,这不是双重检查锁定模式,因为在保持锁定的同时没有写入共享变量

您可能会遇到的主要问题是,由于缓存一致性或寄存器缓存问题,
threadSuspended
false
true
的更改可能不会及时被注意到。寄存器缓存问题是最大的问题(缓存一致性最终会自行解决,尽管它可能需要几微秒),并且在很大程度上取决于周围的代码和优化器的工作


如果这是函数中的独立代码,则不太可能出现寄存器缓存问题。如果threadSuspended已声明为
volatile
,您也不会有问题,因为优化器不会注册缓存
volatile
东西。

关于
--
允许等待()
错误返回,也就是说,没有任何人对对象调用
notify()
。这意味着当
wait()
返回时,可能是,但不一定是,因为有人设置了
threadSuspended
,然后调用了
notify()
。防止这种情况发生的方法是重新检查
threadSuspended
,这就是
while
的作用。

是否应该将其放在Stackoverflow中?我现在已将其标记为movedSee,以供介绍。检查我对有关单例初始化的问题的回答,其中我谈到了DCL:是,OP中的链接在包含代码片段之后的“完整”代码示例中也特别提到了这一点,