Видимость объекта через потоки - PullRequest
2 голосов
/ 03 мая 2009

У меня есть общие сомнения относительно публикации данных и изменений данных в потоках. Рассмотрим для примера следующий класс.

public class DataRace {
  static int a = 0;

  public static void main() {
    new MyThread().start();
    a = 1;
  }

  public static class MyThread extends Thread {
    public void run() { 
      // Access a, b.
    }
  }
}

Позволяет сфокусироваться на main ().

Ясно

new MyThread().start();
a = 1;

Там мы меняем переменную общего доступа a после запуска MyThread и, следовательно, не можем быть потокобезопасной публикацией.

a = 1;
new MyThread().start();

Однако на этот раз изменение a безопасно публикуется в новом потоке, поскольку спецификация языка Java (JLS) гарантирует, что все переменные, которые были видны потоку A при запуске потока B, видны потоку B, фактически как неявная синхронизация в Thread.start ().

new MyThread().start();
int b = 1;

В этом случае, когда новая переменная выделяется после того, как оба потока были созданы, есть ли гарантия, что новая переменная будет безопасно опубликована во всех потоках. т.е. если к var b обращается другой поток, гарантированно ли он будет видеть его значение как 1. Обратите внимание, что я не говорю о каких-либо последующих модификациях b после этого (что, безусловно, должно быть синхронизировано), но первое распределение сделано от JVM.

Спасибо

Ответы [ 6 ]

5 голосов
/ 03 мая 2009

Я не был полностью уверен в этом:

a = 1;
new MyThread().start();

... в том смысле, что я не был уверен, что есть какая-либо гарантия, что значение a будет «сброшено» в общую память до начала нового потока. Тем не менее, спецификация явно говорит об этом. В разделе 17.4.4 указано:

Действие, которое запускает поток, синхронизируется с первым действием в потоке, которое он запускает.

(Обсуждение после этого в основном показывает, что все будет хорошо.)

Я не уверен, о чем идет речь в вашем последнем примере (с b).

1 голос
/ 03 мая 2009

Я не уверен, что вы спрашиваете здесь. Я думаю вы говорите о поточно-ориентированном доступе к переменной "a".

Проблема не в порядке вызова, а в том, что

- доступ к не является потокобезопасным. Таким образом, в примере с несколькими потоками, обновляющими и читающими a, вы никогда не сможете гарантировать, что «a», которое вы читаете, совпадает со значением, из которого вы обновили (какой-то другой поток мог изменить значение).

- в многопоточной среде jvm не гарантирует, что обновленные значения для a будут синхронизированы. Например.

Thread 1: a=1

Thread 2: a=2

Thread 1: print a <- may return 1

Вы можете избежать этого, объявив "volatile".

Как написано, нет никаких гарантий относительно значения a.

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

0 голосов
/ 17 июля 2009

Если b - локальная переменная, созданная в DataRace.main (), как указывает фрагмент кода, она не доступна для MyThread с самого начала, поэтому вопрос спорный.

Если b является общей переменной между основным потоком и потоком MyThread, она не имеет правильной видимости при отсутствии надлежащего барьера памяти, поэтому MyThread может не сразу увидеть правильное значение.

0 голосов
/ 03 мая 2009

У меня есть сомнения по этому вопросу:)

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

В общем, если у вас есть источник, доступ к которому осуществляется с семантикой чтения / записи множеством потоков, вам необходимо будет регулировать доступ к этому ресурсу. (Здесь ресурсом является статическая переменная int DataRace.a)

(я также +1 отмечу здесь Стива Б., что проблема здесь не в порядке вызовов).

0 голосов
/ 03 мая 2009

MyThread (). Start () запускает новый поток, который работает отдельно. Объявление int b = 1 не имеет ничего общего с тем, что вы начали. Это продолжается в основном потоке.

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

0 голосов
/ 03 мая 2009
a = 1;
new MyThread().start();

Присвоение 'a' произойдет до вызова start для нового потока, поэтому новый поток всегда будет печатать значение '1'

new MyThread().start();
a = 1;

В этом случае MyThread может вывести 1 или 0 в качестве значения «a».

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