此问题与旧Java版本的行为以及双重检查锁定算法的旧实现有关

较新的实现使用volatile并依赖于稍微改变的volatile语义,因此它们没有损坏。

声明字段分配始终是原子的,除了long或double字段。

但是,当我阅读解释为什么双重检查锁定被破坏时,据说问题出在赋值操作中:

// Broken multithreaded version

//"Double-Checked Locking" idiom

class Foo {

private Helper helper = null;

public Helper getHelper() {

if (helper == null) {

synchronized(this) {

if (helper == null) {

helper = new Helper();

}

}

}

return helper;

}

// other functions and members...

}

Thread A notices that the value is not initialized, so it obtains the

lock and begins to initialize the

value.

Due to the semantics of some programming languages, the code

generated by the compiler is allowed

to update the shared variable to point

to a partially constructed object

before A has finished performing the

initialization.

Thread B notices that the shared variable has been initialized (or so

it appears), and returns its value.

Because thread B believes the value is

already initialized, it does not

acquire the lock. If B uses the object

before all of the initialization done

by A is seen by B (either because A

has not finished initializing it or

because some of the initialized values

in the object have not yet percolated

to the memory B uses (cache

coherence)), the program will likely

crash.

(from http://en.wikipedia.org/wiki/Double-checked_locking).

什么时候有可能? 在64位JVM上分配操作是否可能不是原子的?

如果否,那么"双重检查锁定"是否真的无效?

在64位JVM上没有区别。

stackoverflow.com/questions/12448864/的可能重复项

问题不是原子性,而是排序。只要不违反之前发生的情况,就允许JVM对指令进行重新排序以提高性能。因此,运行时理论上可以在执行来自类Helper的构造函数的所有指令之前调度更新Helper的指令。

它总是排序,不是吗:)。那就是正确的答案

引用的分配是原子的,但构造不是!因此,如解释中所述,假设线程B希望在线程A完全构造单例之前使用它,它不能创建新实例,因为引用不为null,因此它仅返回部分构造的对象。

If you do not ensure that publishing

the shared reference happens before

another thread loads that shared

reference, then the write of the

reference to the new object can be

reordered with the writes to its

fields. In that case, another thread

could see an up-to-date value for the

object reference but out of date

values for some or all of the object's

state - a partially constructed

object. -- Brian Goetz: Java Concurrency in Practice

由于对null的初始检查未同步,因此没有发布,因此可以重新排序。

java是否先声明了赋值然后才计算正确的部分的地方? (它是Future模式的一种,但我从未见过有关Java编译器使用它的官方声明)。

@罗马:" Java先分配然后才计算正确的部分"不是一件简单的事情。我认为那是不正确的说法。 Java允许低级代码以某种方式对语句进行重新排序,从而在另一个线程访问不是volatile或final的共享字段时导致意外结果。

@罗马看到更新的答案...

那很有意思。

Java中的双重检查锁定存在多种问题:

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

对于Java 5+,如果您声明将字段初始化为volatile(当然,如该论文中所述),它将按预期工作,不会出现问题。

在构造器内部构造Helper的实例可能需要几个分配,并且语义允许相对于分配helper = new Helper()将它们重新排序。

因此,字段Helper可能被分配了对对象的引用,在该对象中并非所有分配都已发生,因此该对象未完全初始化。

您是什么意思"几个作业"?我只看到1:helper = new Helper()。如果可以"就地"构造它,那么您可以提供一个链接来证明java realy确实如此奇怪吗?谢谢。

@Roman:如您的引号中所述,允许编译器生成的代码将Helper分配给尚未完成构造的Helper实例。

阅读本文:http://www.javaworld.com/jw-02-2001/jw-0209-double.html

即使您不了解所有细节(像我一样),也请相信这个好窍门不起作用。

对不起,这可能与问题无关,我很好奇。

在这种情况下,在分配和/或返回值之前获取锁会更好吗?喜欢:

private Lock mLock = new ReentrantLock();

private Helper mHelper = null;

private Helper getHelper() {

mLock.lock();

try {

if (mHelper == null) {

mHelper = new Helper();

}

return mHelper;

}

finally {

mLock.unlock();

}

}

还是使用双重检查锁定有任何优势?

/*Then the following should work.

Remember: getHelper() is usually called many times, it is BAD

to call synchronized() every time for such a trivial thing!

*/

class Foo {

private Helper helper = null;

private Boolean isHelperInstantiated;

public Helper getHelper() {

if (!isHelperInstantiated) {

synchronized(this) {

if (helper == null) {

helper = new Helper();

isHelperInstantiated = true;

}

}

}

return helper;

}

// other functions and members...

}

java 双重检查锁 失效_关于多线程:为什么Java中双重检查锁定被打破?相关推荐

  1. java查看对象锁级别_对象级别锁 vs 类级别锁(Java)

    前言 对于多线程(并发)和Spring Boot这两块在同步进行学习中,在看到使用synchronized关键字使操作同步时,看到和C#中不一样的东西,所以这里呢,就深入学习了下,若有错误之处,还望指 ...

  2. 锁失效_关于bigtable中chubby锁失效时的一点思考

    最近跟国内几家热门公司做分布式存储的大佬们聊了聊,过程十分愉快,但同时也有点小虐.说到底,自己在这个领域并没有很久的经验,很多东西仍停留在知其然而不知其所以然的地步.魔鬼藏在细节之处. 不过这也正好是 ...

  3. java 多线程监听同一个端口_使用多线程在Java服务器中同时侦听两个端口

    我正在构建一个简单的Java服务器,该服务器使用两个ServerSocket实例同时在两个端口上同时侦听客户端请求.这是服务器的代码: import java.io.PrintWriter; impo ...

  4. java实现七日股票问题_七日打卡--JAVA资源限制

    资源限制 资源限制是指在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源. 例如服务器的带宽只有2Mb/s,某个资源的下载速度是1Mb/s每秒,系统启动10个线程下载资源,下载速度不会变成 ...

  5. java加密方式有哪些_面完平安JAVA,他们说了这些

    做平安的职位有4年,接触过N多人选,以下内容是呕心沥血,日积月累整理,希望对大家的面试有帮助. 面试流程: 先说说面试流程,一般至少有3轮,2轮技术+HR面,各个子公司不一样,部份技术会3轮,技术一轮 ...

  6. java什么时候新建进程_创建名为“ {java}”的线程(即轻量级进程)是为了什么?...

    小编典典 所有这些线程都属于JVM. 运行jstack 以获取线程列表. "main" #1 prio=5 os_prio=0 cpu=150.00ms elapsed=8.04s ...

  7. 关于java线程同步的笔记_线程同步(JAVA笔记-线程基础篇)

    在多线程应用程序中经常会遇到线程同步的问题.比如:两个线程A.线程B可能会 "同时" 执行同一段代码,或修改同一个变量.而很多时候我们是不希望这样的. 这时候,就需要用到线程同步. ...

  8. java编写代码用什么_如何学习用Java编写代码:为什么要学习以及从哪里开始

    java编写代码用什么 by John Selawsky 约翰·塞劳斯基(John Selawsky) 如何学习用Java编写代码:为什么要学习以及从哪里开始 (How to learn to cod ...

  9. java 子线程传参_踩坑之Java执行Linux命令死锁阻塞挂起

    1 问题背景 最近在做一个需求需要调用linux下的某个脚本来对ai的模型进行训练,很简单的需求,我像往常一样写下如下的代码片段: Process process = Runtime.getRunti ...

最新文章

  1. 推荐系统数据集大列表
  2. Windows Server 2012 通过RD Web用户自助修改密码
  3. Kibana查询ES显示hits.total.value最大值10000的解决方法
  4. PE文件格式和ELF文件格式(上)----PE文件
  5. mac系统如何在当前目录下打开终端
  6. 手机访问内网IIS服务器网页的方法
  7. fisher线性判别算法python_Fisher线性判别(LDA)python实现
  8. android 百度定位 sdk 3.3demo,BaiduMapApi_Sample_Android_1.3.3\demo无法启动
  9. 为checkedListBox赋值并 遍历checkedListBox中选中的值
  10. hotmail邮箱登录服务器,hotmail邮箱登录页面在哪 hotmail邮箱账号登录设置教程
  11. python io操作不被打断_PyAPNs抛出IOError操作不受devi支持
  12. 使用OLED屏显示汉字
  13. STM32F103X hal RTThread rtc驱动支持日期保存
  14. [生命科学] snapgene 构建载体方法分享
  15. 如何将多个excel表格合并成一个_如何将多个PDF文档合并为一个
  16. 超鸿蒙是什么意思,“志在烟霞慕隐沦,功成归看五湖春。一叶舟中吟复醉,云水。”的意思,诗词全文,作者,上一句和下一句是什么?-选自五代李珣《定风波·志在烟霞慕隐沦》-古诗词名句大全...
  17. 95年计算机专业的电脑,电脑怀旧98年至今20多年买的第一台电脑配置
  18. 木马逆名欺骗:利用unicode控制符RLO
  19. 蓝桥杯-拉马车(C语言)
  20. 股票的股息与股价对比

热门文章

  1. An attempt was made to call the method javax.persistence.PersistenceContext.synchronization()
  2. Scratch (从零开始)- 介绍
  3. HTML5+CSS3小实例:自定义滤镜实现液体加载动画
  4. 【Dubbo实战】基础学习篇(一)
  5. 什么时候使用left join?
  6. loopback地址是什么?怎么配置
  7. C#-MSDN学习提高
  8. 如何在mac下启动mongoDB
  9. MySQL中GROUP_CONCAT函数的使用,separator,将多行查询结果用特定字符串连接起来,适用于一对多
  10. 超详细的C++冒泡排序(升降)的两种实现方式