Java 如何理解之前发生的事情

Java 如何理解之前发生的事情,java,memory-model,Java,Memory Model,在中,它引入了一个概念:发生在一致之前 如果对于A中的所有读取r,其中W(r)是r看到的写操作,则A中的一组操作A在一致之前发生,而不是hb(r,W(r))或A中存在写操作W,从而W.v=r.v和hb(W(r),W)和hb(W,r)“ 在我的理解中,它等于以下词语: …的情况是…和 所以我的前两个问题是: 我的理解正确吗 “w.v=r.v”是什么意思 它也给出了一个例子:17.4.5-1 线程1线程2 B=1;A=2; r2=A;r1=B; 在第一个执行顺序中: 1:B=1; 3:A=2;

在中,它引入了一个概念:发生在一致之前

如果对于A中的所有读取r,其中W(r)是r看到的写操作,则A中的一组操作A在一致之前发生,而不是hb(r,W(r))或A中存在写操作W,从而W.v=r.v和hb(W(r),W)和hb(W,r)“

在我的理解中,它等于以下词语: …的情况是…和

所以我的前两个问题是:

  • 我的理解正确吗
  • “w.v=r.v”是什么意思
它也给出了一个例子:17.4.5-1

线程1线程2
B=1;A=2;
r2=A;r1=B;
在第一个执行顺序中:

1:B=1;
3:A=2;
2:r2=A;//看到0的初始写入
4:r1=B;//看到0的初始写入
命令本身已经告诉我们两个线程是交替执行的,所以我的第三个问题是:左数是什么意思

根据我的理解,r2和r1都可以看到0的初始写入是因为A和B都不是易失性字段。所以我的第四个问题是:我的理解是否正确

在第二执行顺序中:

1:r2=A;//看到A=2的写入
3:r1=B;//看到B=1的写入
2:B=1;
4:A=2;
根据一致性之前发生的定义,不难理解这个执行顺序是一致性之前发生的(如果我的第一个理解是正确的)。
所以我的第五个和第六个问题是:这种情况存在吗在现实世界中?如果是的话,你能给我一个真实的例子吗?

每个线程都可以位于不同的内核上,拥有自己的私有寄存器,Java可以使用这些寄存器来保存变量的值,除非你强制访问一致的共享内存。这意味着一个线程可以写入存储在寄存器中的值,而这个值对于另一个线程来说是不可见的线程运行一段时间,如循环或整个函数的持续时间。(毫秒并不少见)

一个更极端的例子是,读取线程的代码经过优化,假设它从不更改值,因此不需要从内存中读取。在这种情况下,优化后的代码从未看到其他线程执行的更改

在这两种情况下,使用
volatile
可以确保读写顺序一致,并且两个线程看到相同的值。这有时被描述为总是从主内存中读取,但不一定是这样,因为缓存可以直接相互通信。(因此,对性能的影响比您预期的要小得多)


在普通CPU上,缓存是“一致的”(不能保存过时/冲突的值)和透明的,不能手动管理。使线程之间的数据可见只意味着在asm中执行实际加载或存储指令以访问内存(通过数据缓存),并可选择等待存储缓冲区耗尽以提供排序wrt。其他后续操作。

Java内存模型定义了程序所有操作的偏序,该操作在调用之前发生。
为了保证线程
Y
能够看到操作
X
的副作用(如果
X
是否发生在不同的线程中,则不相关),在定义
X
Y
之间的关系之前会发生一个事件
如果不存在这种关系,JVM可能会重新安排程序的操作。
现在,如果一个变量由多个线程共享和访问,并且(至少)由一个线程写入(如果读取和写入不是按“发生之前”关系排序的话),那么就存在数据竞争。
在正确的程序中,没有数据竞争。
例如,在锁
X
上同步了两个线程
A
B
线程A
获取锁(现在
线程B
被阻止)并且执行写操作,然后释放锁
X
。现在
线程B
获取锁
X
,并且由于
线程A
的所有操作都是在释放锁
X
之前完成的,因此它们在线程
A之后获取锁的
线程B
的操作之前排序(对
线程B
也可见)。

请注意,这发生在同一个锁上同步的操作上。在不同锁上同步的线程之间没有实质上正确的before关系。主要的一点是:除非使用某种形式的同步,否则不能保证在程序中的写入之后会发生读操作r看到了写的效果,因为语句可能被重新排序

现实世界中是否存在这种情况(读-看-写,稍后发生)?如果存在,你能给我一个真实的例子吗

显然,从挂钟的角度来看,读操作看不到尚未发生的写操作的效果


从程序顺序的角度来看,因为如果没有适当的同步(发生在关系之前),语句可以重新排序,在程序中写入之前的读取,在执行过程中可以看到写入的效果,因为它是在JVM写入之后执行的。

让我们看一下并发理论中的定义:

原子性-是一种操作属性,可以作为单个事务完全执行,不能部分执行。例如
原子操作

可见性-如果一个线程进行了更改,则其他线程可以看到这些更改。
volatile
在Java 5之前,在
之前发生

排序-编译器能够更改源代码的操作/指令顺序,以进行一些优化

例如
发生在
之前,这是一种
记忆障碍
If value by A(address) == O(old value) then put N(new value) into A(address), 
else O(old value) = value from A(address) and repeat this actions again
// Definitions
int a = 1;
int b = 2;
volatile boolean myVolatile = false;

// Thread A. Program order
{
    a = 5;
    b = 6;
    myVolatile = true; // <-- write
}

//Thread B. Program order
{
    //Thread.sleep(1000); //just to show that writing into `myVolatile`(Thread A) was executed before

    System.out.println(myVolatile); // <-- read
    System.out.println(a);  //prints 5, not 1
    System.out.println(b);  //prints 6, not 2
}