Search code examples
javamultithreadingstaticsynchronizedjava-threads

How to synchronize the shared variables to make this program safe?


I just read the book Java Concurrency in Practice and it displays an unsafe program:

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

The book reads:

Synchronization also has another significant, and subtle, aspect: memory visibility. We want not only to prevent one thread from modifying the state of an object when another is using it, but also to ensure that when a thread modifies the state of an object, other threads can actually see the changes that were made. But without synchronization, this may not happen.

So I understand that even if there are no concurrent writes, data shared between thread, like written to by one thread and read by another thread, needs to be synchronized so as to be published by the writing thread to the reading thread. A writing thread could start another thread which would loop a read on a data written to by the writing thread after it had started the reading thread. The data may be shared or it may not. If the data is several variables then some may be shared and not others, and the sharing order may vary. All data shared between threads should be synchronized. If the folowing program didn't use the synchronized block, then the reader thread may not see a ready true, or it may see it true after seeing its number set. Data not being synchronized would become stale to a thread. To avoid stale data, it must be synchronized during write access but also during read access. Only synchronizing the write access would not prevent the data from being stale.

I wonder how to use the synchronize statement to make this example program safe.


Solution

  • This will synchronize the variable reads and writes so they'll be visible, it uses the same lock (on the FixedVisibility class) to access and change the static variables.

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