Обновленное значение изменчивой переменной не видимо другим потокам - PullRequest
1 голос
/ 13 марта 2019

В следующем фрагменте кода используются несколько потоков для подсчета до 100 миллионов с помощью AtomicInteger.У меня есть 10 потоков Writer для имитации конкуренции за запись и одного потока Reader для имитации конкуренции за чтение.Writer и Reader также совместно используют volatile логическую переменную как яд таблетки .

Однако, только поток Reader может выйти, а Writers - нет.Несмотря на то, что переменная объявлена ​​как volatile, почему потоки Reader не могут видеть обновленное значение?

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: если я заключаю логическое значение в объект, оно работает.

Ответы [ 2 ]

1 голос
/ 13 марта 2019

ваш volatile boolean data НЕ является ссылкой, которую, я думаю, вы пытаетесь предложить здесь, а копией.Таким образом, данные в Reader никогда не будут установлены на false.Если вы используете Writer.data в Reader (и делаете его общедоступным), это должно работать.

0 голосов
/ 13 марта 2019

Логическое является неизменным .

data = true;

Приведенная выше строка в Writer по существу создает новый логический экземпляр, в результате чего читатели никогда не видят новое значение, так как ничего не было «обновлено» в их логической ссылке.

Протестировано это путем замены всех логических вхождений в моем коде пользовательским классом, как показано ниже, и потоки Reader могут видеть обновленное значение.

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;
    }
}
...