>假设我有一个共享的类对象:
class Shared {
private int x = 0 ;
private int y = 0 ;
private Semaphore s = new Semaphore() ;
public int readX() {
s.p() ;
int x0 = x ;
s.v() ;
return x0 ; }
public void writeX(int x0) {
s.p() ;
x = x0 ;
s.v() ; }
public int readY() {
s.p() ;
int y0 = y ;
s.v() ;
return y0 ; }
public void writeY(int y0) {
s.p() ;
y = y0 ;
s.v() ; } }
这里的信号量是一个使用同步方法来提供互斥的类。
现在将执行以下操作:
- 线程 0 调用 o.readX() 并发现它是 0。
- 线程 1 使用 o.writeX(1) 将 1 写入 x,然后写入 1 到 y; o.writeY(1) ;
- 线程 0 调用 o.readY() 得到 1,然后调用 o.readX() 。
线程 0 能否从其缓存中读取并发现 x 为 0?为什么?
编辑
这是信号量类
class Semaphore {
private boolean available = true ;
public synchronized void v() {
available = true ; notifyAll() ; }
public synchronized void p() {
while( !available ) try{ wait() ; } catch(InterruptedException e){}
available = false ; }
}
根据JMM的说法,以下顺序严格按发生前关系排序,因此保证在步骤1中完成的更改对步骤4的读者的可见性:
- 写入 X
- 退出由监视器 M 保护的同步块
- 进入由监视器 M 保护的同步块
- 从 X 读取
,在从变量读取之前获取监视器发生。
因此,如果 p
和 v
同步,则线程 0 将看到更改为 x。
并
排显示两个线程的操作:
线程 1 线程 2o.readX();0 o.writeX(1);o.readY();1 o.writeY(1);o.readX();必须为 1在对
任意选择的 Semaphore
方法的任何调用对进行排序之前,有一个严格的发生顺序,因为它们都在同一个共享Semaphore
实例上经历一个获取-发布周期。
我们有:
- 线程 2
o.writeX(1)
发生在o.writeY(1)
之前; - 线程 2 的
o.writeY(1)
发生在线程 1o.readY() -> 1
之前; - 线程 1 的
o.readY()
发生在线程 1 的第二个o.readX()
之前; - 因此,线程 2 的
o.writeX(1)
发生在线程 1 的第二个o.readX()
之前; - 因此,第二个
o.readX()
的结果必须是 1。