Java 什么是;随后改为;在易变变量的上下文中是什么意思?
Java说: 对易失性字段的写入发生在对该字段的每次后续读取之前Java 什么是;随后改为;在易变变量的上下文中是什么意思?,java,multithreading,cpu-architecture,Java,Multithreading,Cpu Architecture,Java说: 对易失性字段的写入发生在对该字段的每次后续读取之前 我搞不清楚在多线程上下文中后续操作意味着什么。这句话是否暗示了所有处理器和内核的全局时钟。例如,我给某个线程的循环c1中的变量赋值,然后第二个线程可以在随后的循环c1+1中看到这个值 这意味着,一旦某个线程写入一个易失性字段,所有其他线程将(在下一次读取时)观察该写入值;但这并不能保护你免受种族歧视 线程有自己的缓存,这些缓存将失效,并通过缓存一致性协议用新写入的值更新 编辑 “后续”是指在写入本身之后发生的任何情况。因为你不知道
我搞不清楚在多线程上下文中后续操作意味着什么。这句话是否暗示了所有处理器和内核的全局时钟。例如,我给某个线程的循环c1中的变量赋值,然后第二个线程可以在随后的循环c1+1中看到这个值 这意味着,一旦某个线程写入一个易失性字段,所有其他线程将(在下一次读取时)观察该写入值;但这并不能保护你免受种族歧视 线程有自己的缓存,这些缓存将失效,并通过缓存一致性协议用新写入的值更新 编辑 “后续”是指在写入本身之后发生的任何情况。因为你不知道确切的周期/时间,你通常会说当其他线程观察写操作时,它会观察写操作之前所做的所有操作;因此,volatile在保证发生之前就建立了 有点像一个例子:
// Actions done in Thread A
int a = 2;
volatile int b = 3;
// Actions done in Thread B
if(b == 3) { // observer the volatile write
// Thread B is guaranteed to see a = 2 here
}
您也可以循环(旋转等待),直到看到3为止。这更像是对不会发生的事情的定义,而不是将发生的事情的定义 本质上是说,一旦对
原子
变量执行了写入,就不会有任何其他线程在读取该变量时读取过时的值
考虑以下情况
- 线程A不断递增
原子
值
A
- 线程B偶尔读取
,并将该值作为 非原子的A.A
变量b
- 线程C偶尔读取
和A.A
B.B
a
是原子的
,从C的角度来看,b
有时可能小于a
,但永远不会大于a
如果a
不是原子,则无法提供此类保证。在某些缓存情况下,C随时都有可能看到b
超出a
的进度
这是一个简单的演示,演示了Java内存模型如何允许您对多线程环境中可能发生和不可能发生的事情进行推理。在现实生活中,读写数据结构之间的潜在竞争条件可能要复杂得多,但推理过程是相同的。在我看来,它似乎在说它在线程之间提供了无锁获取/释放内存排序语义。请参阅(主要是C++),但文章的要点是语言中性和概念。 事实上,Java
volatile
提供了顺序一致性,而不仅仅是acq/rel。不过,没有实际的锁定。请参阅Jeff Preshing的文章,了解为什么命名与锁匹配。)
如果一个读者看到了你写的值,那么他就知道在写之前生产者线程中的一切都已经发生了 此订购保证仅与关于在单个线程内订购的其他保证结合使用。 e、 g 制作人:
data[0..99] = stuff;
// release store keeps previous ops above this line
data_ready = true;
消费者:
while(!data_ready){} // spin until we see the write
// acquire-load keeps later ops below this line
int tmp = data[99]; // gets the value from the producer
如果data\u ready
不是易失性的,则读取它不会在两个线程之间建立“先发生后发生”关系
您不必使用spinloop,您可以从volatile int
读取序列号或数组索引,然后读取数据[i]
我不太懂Java。我认为
volatile
实际上提供了顺序一致性,而不仅仅是发布/获取。顺序发布存储不允许在以后加载时重新排序,因此在典型的硬件上,它需要一个昂贵的内存屏障,以确保在允许执行任何后续加载之前刷新本地核心的存储缓冲区
详细说明volatile
为您提供的订购信息
Javavolatile
只是一个排序关键字;它不等同于C11\u原子的
,也不等同于它还提供了原子的RMW操作。在Java中,volatile\u var++
不是一个原子增量,它是一个单独的加载和存储,就像volatile\u var=volatile\u var+1
。在Java中,需要像AtomicInteger
这样的类来获得原子RMW
请注意,C/C++volatile
根本不意味着原子性或有序性;它只告诉编译器假定可以异步修改该值。除了最简单的情况外,这只是编写无锁内存所需的一小部分。给出了Java内存模型设计的基本原理。在这个回答中,我试图仅使用JLS中定义的概念进行解释
在Java中,每个线程都由一组操作组成。
其中一些操作可能会被其他线程观察到(例如,编写共享变量),这些 这些操作称为同步操作 线程操作在源代码中的写入顺序称为程序顺序。
订单定义了之前和之后的内容(或者更好,不是之前) 在线程中,每个操作都有一个“发生在之前”关系(由 我搞不懂后续在多线程上下文中意味着什么。这句话是否暗示了所有处理器和内核的全局时钟 后来的意思(根据字典)是指在时间之后。当然有一个glob
while(!data_ready){} // spin until we see the write
// acquire-load keeps later ops below this line
int tmp = data[99]; // gets the value from the producer
Thread 1 Thread 2
A0 A'0
A1 A'1
A2 A'2
A3 A'3
Thread 1 Thread 2
A0 A'0
S1 A'1
A1 S'1
A2 S'2
S2 A'3
S1 < S2 < S'1 < S'2
S1 < S'1 < S'2 < S2
S'1 < S1 < S'2 < S'2
Time Thread-1 Thread-2
1 a = 1;
2 b = 2;
3 x = a;
4 y = b;
5 c = a + b; z = x + y;