Может быть volatile, может быть проблематично, даже если есть один поток записи - PullRequest
0 голосов
/ 10 апреля 2019

Если существует один поток записи и один поток чтения, можем ли мы все еще иметь условие состязания с изменчивой переменной. Как и в приведенном ниже коде, возможно, что в одном случае поток записи проверяет значение x как ноль, при этом переключение контекста не происходит, и поток чтения также видит значение x как 0. В то время как в одном случае поток записи проверяет значение x, поскольку ноль увеличивает его на 1, он сбрасывает его в основную память (поскольку x является энергозависимым), происходит переключение контекста, и поток чтения видит значение x как 1. Мне просто было интересно, будет ли volatile достаточным в этом случае или нам нужно использовать синхронизированный режим, чтобы избежать состояния гонки

Я пытался выполнить приведенный ниже код, но он всегда дает один и тот же результат

public class VolatileSingleWriterClarity {
    static volatile int x = 0;

    public static void main(String[] args) {
        new Thread(VolatileSingleWriterClarity::writer).start();
        new Thread(VolatileSingleWriterClarity::reader).start();
    }

    public static void reader() {
        System.out.println(x);
    }

    public static void writer() {
        x++;
    }
}

1 Ответ

1 голос
/ 10 апреля 2019

Как и в приведенном ниже коде, возможно, что в одном случае поток записи проверяет значение x как ноль, при этом переключение контекста не происходит, и поток чтения также видит значение x как 0.

Да, это абсолютно возможно.Несмотря на то, что x является энергозависимым, x++ включает в себя две совершенно разные операции: энергозависимое чтение, затем энергозависимая запись.Каждая из этих операций является атомарной, но между ними абсолютно возможно переключение контекста.(Также возможно, чтобы два потока работали на совершенно разных процессорных ядрах, так что даже без переключения контекста возможно, что читатель может прочитать исходное значение, в то время как автор только собирается записать новое значение.)


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

synchronized победздесь не очень помогает.Вы, похоже, беспокоитесь о том, чтобы предотвратить этот сценарий (что volatile позволяет, но synchronized может предотвратить):

  • поток записи читает исходное значение x
  • поток чтения читаетисходное значение x, печатает его
  • поток записи пишет новое значение x, которое никогда не читается

, но оно точно эквивалентно этому сценарию (который оба * 1032)* и synchronized allow):

  • поток чтения читает исходное значение x, печатает его
  • поток записи читает исходное значение x
  • поток записи пишет новое значение x, которое никогда не читается

, поэтому нет смысла «исправлять» одно без исправления другого.

Если вы хотите убедиться, чтоПоток читателя не читает x до тех пор, пока поток записи не будет записан в него, вам нужно будет сделать что-то более сложное, например, используя wait и notify.

...