Как свойство «до появления» относится к видимости и порядку? - PullRequest
3 голосов
/ 18 октября 2019

Хотелось бы получить некоторую ясность в отношении того, что именно означает свойство случается до.

Я видел объяснения, что свойство случается раньше говорит о том, что обновления глобальных переменных (которые не являются изменчивыми или заключены вблок синхронизации) становятся видимыми для других потоков, если они изменены перед какой-либо другой переменной, которая является изменчивой или измененной в блоке синхронизации. Это правильно? Если да, то где в документации по Java это сказано?

Насколько я понимаю, свойство "происходит до" определяет связь между общими полями и выполнением кода, например:

  • разблокировкамонитора - перед каждой последующей блокировкой того же монитора.
  • происходит запись в энергозависимое поле - перед каждым последующим чтением этого же поля.
  • вызов для запуска в потокепроисходит до любого действия в запущенном потоке.
  • все действия в потоке происходят до того, как какой-либо другой поток успешно вернется из соединения в этом потоке.

Например:

class Shared {

  private int y = 0;
  private volatile int x = 0;

  public void setOne() {
    y = 1;
    x = 1;
  }

  public int getY() {
    return y;
  }

}

Для приведенного выше кода заданы 2 потока:

Shared shared = new Shared();

new Thread(() -> shared.setOne()).start();
new Thread(() -> shared.getY()).start();

Редактировать Если предположить, что мы можем гарантировать, что первый поток запущен, getY () вернет 0 или1 здесь?

Я также видел примеры, говорящие, что такое поведение происходит только после чтения изменяемого поля в потоке. Таким образом, в этом случае, если один поток читает значение изменяемого поля (скажем, потока B), тогда все поля, записанные перед этим изменяемым полем в потоке A, доступны для потока B. В соответствии с этим, если я изменю метод getY () вОбщий объект сверху должен быть:

  public int getXPlusY() {
    int local = x;
    return local + y;
  }

Это действие делает y видимым для другого потока?

Ответы [ 2 ]

2 голосов
/ 18 октября 2019

Давайте сначала рассмотрим ваш второй пример.

class Shared {

  private int y = 0;
  private volatile int x = 0;

  public void setOne() {
    y = 1; //(1)
    x = 1; //(2)
  }

  public int getXPlusY() {
    int local = x; //(3)
    return local + y; //(4)
  }
}

Мы знаем, что происходит до отношения между (1) и (2) из-за программы order :

Если x и y являются действиями одного потока и x предшествует y в программном порядке, то hb (x, y).

Поскольку x является изменчивым, мы знаем, что между (2) и (3)

1018 *

есть запись до-* *1019* A запись в энергозависимое поле (§8.3.1.4) происходит перед каждым последующим чтением этого поля.

И существует случайное до отношение между (3) и (4) из-за программного порядка снова:

Если x и y являются действиями одного потока и x предшествует y в программном порядке, то hb (x, y).

Поэтому, у нас есть случается, прежде чем цепь (1) → (2), (2) → (3), (3) → (4)

И так как происходит -до - транзитивное отношение (если А происходит до В и Впроисходит до C, затем A происходит до C), что означает, что (1) имеет отношение случай-до с (4) .

Теперь давайте посмотрим наПервый пример:

class Shared {

  private int y = 0;
  private volatile int x = 0;

  public void setOne() {
    y = 1; //(1)
    x = 1; //(2)
  }

  public int getY() {
    return y; //(3)
  }
}

Опять существует отношение до-10 * * между (1) и (2), но это все. Поскольку x не читается во втором потоке, у нас нет Случаев до между (2) и (3). Таким образом, у нас есть нет отношения до 10 * * между (1) и (3) .

Цитаты взяты из Глава 17 Спецификации языка Java(JLS)

0 голосов
/ 18 октября 2019

Это правильно? Если да, то где в документации по Java это сказано?

Да, это верно - спецификации Java говорят это в JLS 17.4.5. Происходит до:


В приведенном вами примере между двумя нитями идет гонка. Кроме того, чтобы поток 2 мог видеть, что сделал поток 1, поток 2 должен прочитать x (переменная) перед чтением y. Если thread2 читает только y, что не является энергозависимым, тогда видимость измененного значения y не гарантируется.


Вы можете изменить пример кода, как показано ниже. Гонка еще продолжается, поэтому результат может быть x=0 y=0, x=0 y=1 или x=1 y=1. Но использование volatile гарантирует, что программа никогда не выдаст x=1 y=0.

public class UseVolatile {
    public static void main(String[] args) {
        Shared shared = new Shared();
        new Thread(() -> shared.setOne()).start();
        new Thread(() -> {
            int x = shared.getX();
            int y = shared.getY();
            System.out.printf("x=%d y=%d%n", x, y);
        }).start();
    }
}
class Shared {
    private int y = 0;
    private volatile int x = 0;

    public void setOne() {
        y = 1;
        x = 1;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
}

Редактировать

Мы можем понять, почему вывод x=1 y=0 может 'это случилось. Ссылаясь на JLS:

Два действия могут быть упорядочены с помощью отношения «до того». Если одно действие происходит до другого, то первое видно и упорядочено перед вторым.

Если у нас есть два действия x и y, мы пишем hb (x, y), чтобы указать, что x происходит раньшеy.

Если x и y являются действиями одного потока и x предшествует y в программном порядке, то hb (x, y). (1)

Если hb (x, y) и hb (y, z), то hb (x, z). (2)

Запись в энергозависимое поле происходит перед каждым последующим чтением этого поля. (3)

Действия, происходящие в одних и тех же потоках, упорядочены по (1). Таким образом, запись в y происходит до записи в x в потоке 1.

Запись в volatile x в потоке 1 происходит до чтения обновленного значения x в потоке 2, посколькув (3).

И чтение x происходит - перед чтением y в thread2, из-за (1).

Объединяя все это, следует, что если thread2 видитобновленное значение для x, тогда произойдет чтение y в этом потоке - перед записью в y в другом потоке (и видимость обновленного значения гарантируется).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...