简体   繁体   English

内存可见性,无需同步或不稳定

[英]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: 因此,两种情况都适用:

  1. Exiting with printing 1: Once of the i++ operations completed and the resulf of the get was one. 退出打印1: i++操作完成一次后,get的操作就完成了。
  2. Both 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.

相关问题 易失性数组 - 元素的内存可见性 - Volatile array - memory visibility of the elements 具有易失性写功能的本地内存可见性 - local memory visibility with volatile write Java内存模型中的同步和易失性如何工作? - How synchronized and volatile work in Java memory model? Java中synchronized/volatile的变量可见性影响程度是多少 - What is the extent of variable visibility effect of synchronized/volatile in Java Java中的易失性数组和内存障碍以及可见性 - Volatile arrays and memory barriers and visibility in Java 两个相关易失变量的内存可见性语义 - Memory visibility semantics of two related volatile variables 易失性和同步 - Volatile and Synchronized Java内存模型,易失性和同步块访问非易失性变量 - Java Memory Model, volatile, and synchronized blocks accessing non-volatile variables Java 并发实践“清单 7.1。使用 volatile 字段来保持取消状态。”。 同步可见性? - Java Concurrency in Practice "Listing 7.1. Using a volatile field to hold cancellation state.". synchronized for visibility? 在多个线程之间传递 POJO(无易失性字段,同步方法)并确保更改可见性的正确方法? - Correct way to pass a POJO (no volatile fields,synchronized methods) between multiple threads and assure visibility of changes?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM