Search code examples
javamultithreadingvolatile

Simulating Field-visibility problem in Java


I was going through one of the tutorials on memory model of Java and came across this concept of field visibility which happens in multi-threaded programming. I tried to simulate the same using the below code, however , I see in each thread, the latest value is being reflected (in ReaderThread).

The below is the complete program.

Edit

After some suggestion to use while(somevariable), I incorporated, but still getting the same behaviour. I removed sysout on reading the x

FieldVisibility.java

package com.example.threads.fieldvisibility;

public class FieldVisibility {

    private int x;

    private boolean condition;

    public FieldVisibility() {
        condition = true;
    }

    public void reader() {

        System.out.println("x in reader() is " + x);
    }

    public void writer() {
        x++;

    }

    public boolean getCondition() {
        return condition;
    }

    public void setCondition(boolean condition) {
        this.condition = condition;
    }
}

ReaderThread.java

package com.example.threads.fieldvisibility;

public class ReaderThread extends Thread {

    private FieldVisibility fv;

    public ReaderThread(FieldVisibility fv) {
        this.fv = fv;

    }

    @Override
    public void run() {

        while (fv.getCondition()) {

            System.out.println("It mean condition is true, which was set initially");

        }
        for (;;) {

        }
    }
}

WriterThread.java

package com.example.threads.fieldvisibility;

public class WriterThread extends Thread {

    private FieldVisibility fv;

    public WriterThread(FieldVisibility fv) {
        this.fv = fv;

    }

    @Override
    public void run() {

        fv.setCondition(false);
        for (;;) {

            fv.writer();
        }

    }
}

MainApp.java

package com.example.threads.fieldvisibility.main;

import com.example.threads.fieldvisibility.FieldVisibility;
import com.example.threads.fieldvisibility.ReaderThread;
import com.example.threads.fieldvisibility.WriterThread;

public class MainApp {

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

        FieldVisibility fv = new FieldVisibility();

        ReaderThread rt = new ReaderThread(fv);
        WriterThread wt = new WriterThread(fv);

        wt.start();

        rt.start();

        Thread.sleep(999999999L);
    }
}

Edit

I added a new variable condition in FieldVisibility, whose default values is true. Next, I set its value to false in WriterThread, however, the same value (false) is still propagated to ReaderThread, so I still am not able to simulate it.

Original I expected that at some time ReaderThread won't be able to "see" the latest value of variable x, but I saw every time I run it, it gave same results. I even run in debug mode, suspended ReaderThread while running WriterThread continuously. But that also didn't prevent ReaderThread to have latest values. I expected that I need to declare variable x as volatile in order for ReaderThread to read latest values of x.

How can I simulate the field visibility concept, or what changes I need to do for this?


Solution

  • Your example doesn't work because System.out.println() uses a shared resource (System.out), so it will synchronize with other uses of the same resource.

    Therefore you will never* see a result where one thread uses the old value of the other. (*in theory it is possible for the reader to read x between x++ and the corresponding System.out.println()

    Here is an example where a old value is used:

    public class ThreadVisibility implements Runnable {
    
        private boolean stop = false;
    
        @Override
        public void run() {
            while (!stop);
        }
    
        public static void main(String[] args) throws InterruptedException {
            ThreadVisibility test = new ThreadVisibility();
            Thread t = new Thread(test);
            t.setDaemon(true);
            System.out.println("Starting Thread");
            t.start();
            Thread.sleep(1000);
            System.out.println("Stopping Thread");
            test.stop = true;
            t.join(1000);
            System.out.println("Thread State: " + t.getState());
        }
    }
    

    If you run this code, it will display that the thread is still running at the end. Without the t.setDaemon(true), the VM would wait for the Thread to finish, which would never happen.

    If you comment out the Thread.sleep, then the new Thread may terminate (at least it did in my tests), but it is not guaranteed to.
    The right fix for this problem is to declare stop volatile.
    Or add a memory barrier.