-1

whether the private member variable value in class Result need to be modified by volatile

public class Main {

    public static void main(String[] args) throws InterruptedException {
        Result result = new Result();

        synchronized (result) {
            new Thread(new Task1(result)).start();
            new Thread(new Task1(result)).start();
            new Thread(new Task1(result)).start();
            new Thread(new Task1(result)).start();
            new Thread(new Task1(result)).start();
            new Thread(new Task2(result)).start();
            new Thread(new Task2(result)).start();
            new Thread(new Task2(result)).start();
            new Thread(new Task2(result)).start();
            new Thread(new Task2(result)).start();
            new Thread(new Task2(result)).start();

            result.wait(1500);
        }

        System.out.println(result.getValue());
        System.out.println("Finished");
    }
}

class Result {
    private Integer value;

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }
}

class Task1 implements Runnable {
    private final Result result;

    public Task1(Result result) {
        this.result = result;
    }

    @Override
    public void run() {
        try {
            // call function1
            Thread.sleep(1010);
            if (result.getValue() == null) {
                synchronized (result) {
                    if(result.getValue() == null) {
                        result.setValue(new Integer(10000));
                        System.out.println("####: 1");
//                throw new InterruptedException();
                        result.notify();
                    }

                }
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Task2 implements Runnable {

    private final Result result;

    public Task2(Result result) {
        this.result = result;
    }

    @Override
    public void run() {
        try {
            // call function2
            Thread.sleep(1000);
            if (result.getValue() == null) {
                synchronized (result) {
                    if(result.getValue() == null) {
                        result.setValue(new Integer(2000000));
                        System.out.println("####: 2");
                        result.notify();
                    }
                }
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Allme
  • 23
  • 4
  • Unless you wait for all Threads to be finished the result will not be correct. Consider using `Thread::join` or by using `ExecutorService ` – Scary Wombat Nov 25 '21 at 07:02
  • 2
    You are asking the wrong question here. There is no rule that says `volatile` "must" be used. But yes ... `volatile` would be one way to ensure that the latest value of `value` is returned by `getValue()`. (But not the only way.) – Stephen C Nov 25 '21 at 07:19
  • 2
    Rather than asking for / looking for a simplistic rule (which doesn't exist) on when `volatile` is required, you should probably be reading a comprehensive tutorial on writing concurrent Java code. Or better still ... the definitive textbook. – Stephen C Nov 25 '21 at 07:27
  • There's more to the code than a missing or not missing `volatile`. – Felix Nov 25 '21 at 15:08

1 Answers1

-1

The Java volatile keyword is used to mark a Java variable as "being stored in main memory". More precisely that means, that every read of a volatile variable will be read from the computer's main memory, and not from the CPU cache, and that every write to a volatile variable will be written to main memory, and not just to the CPU cache.

You have multiple threads using the same object. Which means that there is a chance that they will read the value of this field from the CPU cache. Therefore, you need to use volatile.

Here's a more detailed guide with some background.

Does this solve your problem ? Let me know in the comments.

Arthur Klezovich
  • 2,595
  • 1
  • 13
  • 17
  • Thinking in terms of flushing to main memory is flawed; this is not how CPUs work. CPU caches are always coherent; main memory is just a spill bucket for whatever doesn't fit in the cache. Apart from that, the JMM is not an operational model and hence not expressed in terms of caches and main memory. It is an axiomatic model and the most visible part of the model is (happens before) consistency; which is based on some happens before relation. Happens before consistency defines which values a read is allowed to see. – pveentjer Nov 27 '21 at 12:56
  • In the above case, there is no happens-before edge between the write and read of Result.value. This causes a data race and therefore this program is incorrectly synchronized. – pveentjer Nov 27 '21 at 12:58