Diskun Zhu
Diskun Zhu

Reputation: 115

Sharing variable without synchronization

I read it from Java Concurrency in Practice, that it is bad to share variables in threads without synchronisation. However, for some examples as following which only have one read thread and one write thread, I can't find errors in it. From my perspective, the result for the following program will definitely terminate and print 42 because ReaderThread can go through only when ready becomes true, and that means number is 42. Could somebody give me some explanation why I am wrong?

public class NoVisibility {
    private static boolean ready;
    private static int number;
    private static class ReaderThread extends Thread {
            public void run() {
                while (!ready)
                    Thread.yield();
                System.out.println(number);
            }
    }
    public static void main(String[] args) {
        new ReaderThread().start();
        number = 42;
        ready = true;
    } 
}

Upvotes: 3

Views: 578

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074295

You don't need synchronization (e.g., synchronized) in your example (though you do need volatile, more below) because reads and writes of boolean and int variables are always atomic. Which is to say, a thread can't be part-way through writing to a boolean (or int) variable when another thread comes along and reads it, getting garbage. The value being written by one thread is always fully written before another thread can read it. (This is not true of non-volatile double or long variables; it would be entirely possible for a thread to read garbage if it happened to read in the middle of another thread's write to a long or double if they aren't marked volatile.)

But you do need volatile, because each thread can have its own copy of the variables, and potentially can keep using its own copy for a long period of time. So it's entirely possible for your reader thread to wait forever, because it keeps re-reading its own copy of ready which stays false even though your main thread writes true to its copy of ready. It's also possible for your reader thread to see ready become true but keep reading its own copy of number, and so print 0 instead of 42.

You would need to use synchronized if you were modifying the state of an object that doesn't guarantee thread-safe access. For instance, if you were adding to a Map or List. That's because there are multiple operations involved, and it's essential to prevent one thread from reading a half-complete change another thread is making.

Other classes, such as those in java.util.concurrent, offer classes with thread-safe access semantics.

Upvotes: 3

Kayaman
Kayaman

Reputation: 73558

Since ready isn't volatile, there's no guarantee that ReaderThread will see that your main thread has changed it. When you mark ready as volatile, all writes from one thread will be seen in other threads reading it.

You always need some sort of synchronization / visibility control when communicating between threads. Whether it's volatile, explicitly using synchronized or using the java.util.concurrent.* classes.

Upvotes: 3

Related Questions