简体   繁体   中英

Volatile variable's updated value is not visible to other threads

The following snippet of code uses multiple threads to count to 100 million using an AtomicInteger. I have 10 Writer threads to simulate write contention and a single Reader thread to simulate read contention. The Writer and Reader also share a volatile boolean variable as a poison pill .

However, only the Reader thread is able to exit while the Writers are not. Despite declaring the variable as volatile, why aren't the Reader threads able to see the updated value?

public class AtomicRunnerV2 {

    private static final int THREADS = 10;
    private static final Integer MAX_COUNT = 100_000_000;

    public static void main(String[] args) throws Exception {
        AtomicInteger atomicInteger = new AtomicInteger(1);
        Boolean data = new Boolean(false);
        ExecutorService executorService = Executors.newFixedThreadPool(THREADS + 1);
        for (int i = 0; i < THREADS; i++) {
            executorService.submit(new Writer(atomicInteger, data));
        }
        executorService.submit(new Reader(atomicInteger, data));
        executorService.shutdown();
    }

    static class Writer implements Runnable {

        private AtomicInteger integer;
        private volatile Boolean data;

        Writer(final AtomicInteger integer, Boolean data) {
            this.integer = integer;
            this.data = data;
        }

        @Override public void run() {
            while (!data) {
                integer.incrementAndGet();
            }
            System.out.println("count " + integer.get() + " from WRITER!");
        }
    }

    static class Reader implements Runnable {

        private AtomicInteger integer;
        private volatile Boolean data;

        Reader(final AtomicInteger integer, Boolean data) {
            this.integer = integer;
            this.data = data;
        }

        @Override public void run() {
            while (!data) {
                if (integer.get() >= MAX_COUNT) {
                    data = true;
                }
            }
            System.out.println("count " + integer.get() + " from READER!");
        }
    }
}

PS: If I wrap the boolean in an object, it works.

your volatile boolean data is NOT a reference, which I think you are trying to suggest here, but a copy. So the data in Reader will never be set to false. If you use Writer.data in Reader (and make it public), this should work.

Boolean is immutable .

data = true;

The above line in Writer essentially creates a new Boolean instance thereby causing the Readers to never see the new value as nothing was "updated" in their Boolean reference.

Tested this by replacing the all Boolean occurrences in my code with a custom class like below and the Reader threads are able to see the updated value.

static class MyBoolean {

    private boolean value;

    MyBoolean(final boolean value) {
        this.value = value;
    }

    boolean isValue() {
        return value;
    }

    void setValue(final boolean value) {
        this.value = value;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM