2

I have been experimenting Java thread visibility problem with the popular example of sending a stop signal to the thread by means of a shared boolean and non-volatile variable and the target thread does not seem to get it) as below:

public class ThreadVisibilityTest {

    //Shared variable to send a signal to the thread
    static boolean stopped = false;

    public static void main(String[] args) throws Exception {

        Thread targetThread = new Thread(new Runnable() {
                public void run() {
                while(!stopped) {}
                System.out.println("Target thread gets signal and stops...");
                }
                });

        targetThread.start();

        TimeUnit.SECONDS.sleep(5);
        stopped=true;
        System.out.println("Main thread has sent stop signal to the thread...");

    }

}

Main thread sends stop signal to the target thread after 5 seconds by means of setting stopped to true and the target thread can not get it and so does not stop.

Defining stopped variable as volatile obviously solves the problem.

Bu then I realized that if I make stopped variable non volatile but instead access it in a synchronized context in the target thread, target thread gets the final value and stops. So thread visibility problem seems to be solved just like using volatile.

Thread targetThread = new Thread(new Runnable() {
            public void run() {
                while(true) {
                    synchronized(this) {
                        if(stopped) break; 
                    }
                }
                System.out.println("Target thread gets signal and stops...");
            }
        });

And also the object monitor to be used for synchronization seems to have no effect as follows:

synchronized(Thread.class) {
        if(stopped) break; 
}

Is this something that happens by chance or do I miss something? Or can we say that accessing shared variable with mutual exclusion seems to force target thread to refresh its cache memory just like accessing a volatile variable?

If the latter is true which way do you suggest to overcome thread visibility issue, by means volatile keyword or access with mutual exclusion?

Thanks in advance

3
  • If you know that the most up-to-date value of this variable has to be used, why would you choose not to use volatile? What do you see as the problem with it? Commented Nov 6, 2015 at 12:17
  • If you want to use synchronization, you surely have to do the write and read of stopped in blocks synchronized on the same monitor. You don't write the value in a synchronized block. Commented Nov 6, 2015 at 12:26
  • I dont not mean not to choose volatile. I just try to understand why mutual exclusion also solves memory visibility issue as I have tested and seen that accessing a shared variable with mutual exclusion makes you get its final value just like volatile. Commented Nov 9, 2015 at 6:46

5 Answers 5

4

Is this something that happens by chance or do I miss something?

You missed the chapter in the Java Language Reference (JLS) that talks about the Java Memory Model. Either that, or you missed working through the concurrency chapter in the Java tutorial. https://docs.oracle.com/javase/tutorial/essential/concurrency/

Either way, you would have learned that if thread A exits from a synchronized block, and then thread B enters a block that is synchronized on the same object, then everything that thread A wrote before releasing the lock is guaranteed to be visible to thread B after thread B locks the lock.

Sign up to request clarification or add additional context in comments.

Comments

0

I think mutual exclusion also provides memory visibility as stated in Java Concurrency In Practice (By Brian Goetz) in section 3.1.3 Locking and Visibility.

Comments

0

See, you are reading it in synchronized context but not writing in the synchronized context. That might cause problem.

Comments

0

As other answers have already pointed out, memory visibility is established when using synchronization.

However, it would be preferable to use a volatile shared variable (unless synchronization is needed for non visibility related issues) for greater concurrency. Overuse of synchronization forces threads to constantly wait for each other, when it would be safe and faster to work concurrently.

Comments

0

Synchronized blocks or methods work very similarly to volatile variables regarding visibility. After the thread exits the synchronized block, it releases the monitor, which has the effect of flushing CPU registers to CPU cache - so that writes made by that thread are visible to other threads.

Before entering the synchronized block, the thread acquires the monitor, which has the effect of invalidating the local processor cache (CPU registers) and forcing the thread re-read from the CPU cache. Therefore, all changes made by the previous release would be visible to the thread which has the same monitor lock.

In the above example, the write was made outside of synchronized context. In this scenario, according to JMM, there is no guarantee as to when the flush CPU register will occur and - consequently, whether the latest values would be available to other threads.

For this reason, you can assume that the code “works” probably because the flush occurs in time and the synchronized block forces the thread to re-read from CPU cache on each loop. Besides, the JMM states that the “happen-before” visibility guarantee requires the same monitor lock. So, anything beyond that is just by chance.

Source: https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.