我对Java内存模型有疑问。
在以下场景中:
姓名:a = 0; b = 0;
T1:
a = 1;
l.lock();
b = 1;
l.unlock();
T2:
l.lock();
read b;
l.unlock();
read a;
我可以说,b
读取的T2
的值是1
,那么a
读取的T2
的值必须是{{1} }}?
根据我的理解,1
中的unlock
会将T1
和a
的值与主内存和b
中的lock
一起清除确保T2
和read a
都可以获得最新值。
我是对的吗?
编辑:我刚刚指定它们被锁定在同一个锁上。
答案 0 :(得分:2)
如果T2读取的b的值是1,那么T2的读取值是否必须为1?
是。它得到了保证。操作可以将移动到同步块中,但不能输出。请参阅Jeremy Mansons博客文章Roach Motels and The Java Memory Model。
这意味着,虽然read a
可以在unlock
之前向上移动(并且由于指令重新排序而高于read b
),但它永远不会超过lock
指令T2
。
相同的推理适用于a = 1
:它可以向下移动到同步块(由于指令重新排序而在b = 1
之下),但不会传递unlock
指令。
但是,如果我们交换这样的说明,它们都会被锁定,这意味着如果T2
从1
读取b
,那么T1
已经写了1
到b
。
答案 1 :(得分:0)
我从http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html找到了一些有用的信息。
在同步做什么?部分,它说:
'同步确保线程在之前或在同步块期间的内存写入以可预测的方式显示给在同一监视器上同步的其他线程。在我们退出synchronized块之后,我们释放了监视器,它具有将缓存刷新到主内存的效果,因此该线程所做的写操作对其他线程是可见的。在我们进入同步块之前,我们获取监视器,它具有使本地处理器高速缓存无效的效果,以便从主存储器重新加载变量。然后,我们将能够看到之前版本中显示的所有写入内容。'
'这意味着在退出同步块之前对线程可见的任何内存操作在进入受同一监视器保护的同步块后对任何线程都是可见的,因为所有内存操作都在发布之前发生,并且释放发生在获得之前。'