Java:关于 Java 关键字的混淆 "volatile" 在 JLS 中解释
Java: confusion about Java keyword "volatile" explained in JLS
JLS中有例子
关于关键字 volatile.
一个线程重复调用方法一,另一个线程调用方法二。
class Test {
static volatile int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}
This allows method one and method two to be executed concurrently, but guarantees that accesses to the shared values for i and j occur exactly as many times, and in exactly the same order, as they appear to occur during execution of the program text by each thread. Therefore, the shared value for j is never greater than that for i, because each update to i must be reflected in the shared value for i before the update to j occurs. It is possible, however, that any given invocation of method two might observe a value for j that is much greater than the value observed for i, because method one might be executed many times between the moment when method two fetches the value of i and the moment when method two fetches the value of j.
一些问题:
shared values
是什么意思?
- 在什么情况下我们应该使用
volatile
?(因为"any given invocation of method two might observe a value for j that is much greater than the value observed for i")
我从其他文章了解到,如果有一个以上的核心或处理器(我认为重点是多个缓存),"unvolatile"值可能会出问题。
有什么问题吗?为什么?
共享值是 static int i,j
,因为它们可以在许多不同的线程之间共享(这是静态的定义)。当您有多个线程访问同一个变量时,您应该使用 volatile。关于是否仅当一个线程写入该值而其他线程读取该值时才应使用 volatile 存在同样的争论,因为 i += 5
等操作不是原子的,除非您使用 AtomicInteger
(尽管有一个更高的开销)。
当一个线程写入该值而一个(或多个)线程从该值读取时,您应该使用 volatile
的原因是因为如果没有 volatile
关键字,线程将缓存该值并且将使用缓存中的值,该值可能与实际值不一致。 volatile
关键字强制每个线程不缓存该值,而是访问该值的实际内存位置。
此上下文中的共享值是由多个线程操作的变量。
对非易失性变量的访问可以通过实现(编译器或CPU)重新排序,因此结果可能与"naively"预期结果不一致,即顺序执行。使用 volatile,您可以保证对共享变量的访问是串行完成的,与程序顺序执行一致。
在没有锁、信号量或其他互斥原语的保护的情况下,对变量的冲突访问并发进行时,您需要 volatile。如果至少有一个是写入(read/write 或 write/write)并且它们不是按互斥原语或程序顺序排序的,则对同一变量的两个操作是冲突的。
JLS中有例子 关于关键字 volatile.
一个线程重复调用方法一,另一个线程调用方法二。
class Test {
static volatile int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}
This allows method one and method two to be executed concurrently, but guarantees that accesses to the shared values for i and j occur exactly as many times, and in exactly the same order, as they appear to occur during execution of the program text by each thread. Therefore, the shared value for j is never greater than that for i, because each update to i must be reflected in the shared value for i before the update to j occurs. It is possible, however, that any given invocation of method two might observe a value for j that is much greater than the value observed for i, because method one might be executed many times between the moment when method two fetches the value of i and the moment when method two fetches the value of j.
一些问题:
shared values
是什么意思?- 在什么情况下我们应该使用
volatile
?(因为"any given invocation of method two might observe a value for j that is much greater than the value observed for i")
我从其他文章了解到,如果有一个以上的核心或处理器(我认为重点是多个缓存),"unvolatile"值可能会出问题。
有什么问题吗?为什么?
共享值是 static int i,j
,因为它们可以在许多不同的线程之间共享(这是静态的定义)。当您有多个线程访问同一个变量时,您应该使用 volatile。关于是否仅当一个线程写入该值而其他线程读取该值时才应使用 volatile 存在同样的争论,因为 i += 5
等操作不是原子的,除非您使用 AtomicInteger
(尽管有一个更高的开销)。
当一个线程写入该值而一个(或多个)线程从该值读取时,您应该使用 volatile
的原因是因为如果没有 volatile
关键字,线程将缓存该值并且将使用缓存中的值,该值可能与实际值不一致。 volatile
关键字强制每个线程不缓存该值,而是访问该值的实际内存位置。
此上下文中的共享值是由多个线程操作的变量。
对非易失性变量的访问可以通过实现(编译器或CPU)重新排序,因此结果可能与"naively"预期结果不一致,即顺序执行。使用 volatile,您可以保证对共享变量的访问是串行完成的,与程序顺序执行一致。
在没有锁、信号量或其他互斥原语的保护的情况下,对变量的冲突访问并发进行时,您需要 volatile。如果至少有一个是写入(read/write 或 write/write)并且它们不是按互斥原语或程序顺序排序的,则对同一变量的两个操作是冲突的。