[英]memory visibility without synchronized or volatile
Is it correct to say without "synchronized" or "volatile" keyword, changes made by one thread will never be seen by another (or undeteministic)? 说不带“ synchronized”或“ volatile”关键字,一个线程所做的更改将永远不会被另一个线程(或确定性的)看到是正确的吗? I run the the following program many times in multi-core platform and results are different. 我在多核平台上多次运行以下程序,结果却有所不同。 Sometimes the program never terminates, which is the expected scenerio. 有时程序永远不会终止,这是预期的场景。 But sometimes it exits with printing "1". 但有时会退出并显示“ 1”。
JDK: jdk1.8.0_73 JDK:jdk1.8.0_73
OS:CentOS Linux release 7.1.1503 操作系统:CentOS Linux版本7.1.1503
public class VolatileTest implements Runnable {
private int i = 0;
public void run() {
i++;
i++;
}
public int get() {
return i;
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
VolatileTest volatileTest = new VolatileTest();
executorService.execute(volatileTest);
while (true) {
int i = volatileTest.get();
if (i % 2 != 0) { //
System.out.format("i: %s \n", i);
System.exit(0);
}
}
}
}
Is it correct to say without "synchronized" or "volatile" keyword, changes made by one thread will never be seen by another (or non-deterministic)? 说不带“ synchronized”或“ volatile”关键字,一个线程所做的更改将永远不会被另一个(或不确定的)线程看到,这是正确的吗?
The correct statement is that it is unspecified what happens if there is no happens before relationship from the write event to the subsequent read event. 正确的说法是,如果在从写入事件到后续读取事件的关系发生之前没有发生任何事件 ,则未说明会发生什么。
Changes may be immediate, or delayed, or they may never be visible. 更改可能是立即的,也可能是延迟的,或者可能永远都不可见。
And what is more, changes may become visible in an unexpected order. 而且,更改可能会以意外的顺序可见。
In your example, the i
variable can have 3 possible values, and it is unspecified and unpredictable which the main
thread will see. 在您的示例中, i
变量可以有3个可能的值,并且main
线程将看到哪个变量是不确定的和不可预测的。 The behavior that you observe is not unexpected. 您观察到的行为并不意外。
The output of volatileTest.get()
can be 0, 1, or 2
as there is not synchronization and the run method is not atomic. volatileTest.get()
的输出可以为0, 1, or 2
因为没有同步并且run方法不是原子的。 Moreover, each of the i++
operations are not atomic. 而且,每个i++
操作都不是原子的。
Thus both scenarios are applicable: 因此,两种情况都适用:
i++
operations completed and the resulf of the get was one. 退出打印1: i++
操作完成一次后,get的操作就完成了。 i++
instructions completed and the get()
returned a 2 and thus getting stuck in the infinite loop. 两条i++
指令均已完成,并且get()
返回2,从而陷入无限循环。 Is it correct to say without "synchronized" or "volatile" keyword, changes made by one thread will never be seen by another (or non-deterministic)? 说不带“ synchronized”或“ volatile”关键字,一个线程所做的更改将永远不会被另一个(或不确定的)线程看到,这是正确的吗?
It's not correct, this question has been already answered ( this ) 这是不正确的,这个问题已经回答了( this )
The run method it's not atomic/thread-safe/synchronized so, it's enough easy to understand that the assignement int i = volatileTest.get();
运行方法不是原子/线程安全/同步的,因此,很容易理解赋值int i = volatileTest.get();
can get value from 0 to 2. To achieve what you want you should acquire a lock
and realease it after the double increment or just put the keyword synchronized
to the method signature. 可以获取0到2之间的值。要实现所需的功能,您应该获得一个lock
并在两次递增后重新实现它,或者只需将关键字synchronized
到方法签名即可。
without "synchronized" or "volatile" keyword, changes made by one thread will never be seen by another 如果没有“ synchronized”或“ volatile”关键字,则一个线程所做的更改将永远不会被另一个线程看到
This is not correct. 这是不正确的。 The visibility is not defined as it depends on the JRE thread caching implementation. 可见性未定义,因为它取决于JRE线程缓存的实现。
executorService.execute(volatileTest); executorService.execute(volatileTest);
I believe the way how you test the visibility is not the best. 我认为测试可见度的方法不是最好的。 Jusst search stackoverflow and there are multiple examples (some even worse) Jusst搜索stackoverflow并且有多个示例(有些甚至更糟)
The code executes the run() method once (and only once) and there is a small change you will get i==1
depending on the thread cache and thread scheduler 该代码执行一次run()方法(并且仅执行一次),根据线程缓存和线程调度程序的不同,您将获得一小段更改, i==1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.