简体   繁体   中英

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)? 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".
JDK: jdk1.8.0_73
OS:CentOS Linux release 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)?

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. 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. Moreover, each of the i++ operations are not atomic.

Thus both scenarios are applicable:

  1. Exiting with printing 1: Once of the i++ operations completed and the resulf of the get was one.
  2. Both i++ instructions completed and the get() returned a 2 and thus getting stuck in the infinite loop.

Is it correct to say without "synchronized" or "volatile" keyword, changes made by one thread will never be seen by another (or non-deterministic)?

It's not correct, this question has been already answered ( 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(); 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.

without "synchronized" or "volatile" keyword, changes made by one thread will never be seen by another

This is not correct. The visibility is not defined as it depends on the JRE thread caching implementation.

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)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM