переменные статического массива должны быть заблокированы? - PullRequest
0 голосов
/ 16 марта 2011

Допустим, у меня есть статическая переменная, представляющая собой массив размером 5. И, скажем, у меня есть два потока, T1 и T2, они оба пытаются изменить элемент с индексом 0 этого массива.А затем используйте элемент с индексом 0. В этом случае я должен заблокировать массив до тех пор, пока T1 не будет завершен, используя элемент правильно?

Другой вопрос, скажем, T1 и T2 уже запущены, элемент доступа T1 по индексу0 сначала, потом заблокируй.Но затем сразу после того, как T2 пытается получить доступ к элементу с индексом 0, но T1 еще не разблокировал индекс 0.Тогда в этом случае, чтобы T2 получил доступ к элементу с индексом 0, что должен делать T2?должен ли T2 использовать функцию обратного вызова после того, как T1 разблокирует индекс 0 массива?

Ответы [ 7 ]

1 голос
/ 17 марта 2011

Рассматривали ли вы использование AtomicReferenceArray? http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/atomic/AtomicReferenceArray.html Он предоставляет метод #getAndSet, который обеспечивает потокобезопасный атомарный способ обновления индексов.

1 голос
/ 17 марта 2011
T1 access element at index 0 first, then lock it.

Сначала заблокируйте статическую переменную mutex, затем получите доступ к вашей статической переменной.

 static final Object lock = new Object();
 synchronized(lock) {
   // access static reference
 }

или лучший доступ по справочному классу

synchronized(YourClassName.class) {
     // access static reference
}
1 голос
/ 16 марта 2011

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

В C ++ обычно используется RAII, чтобы гарантировать, что блокировка освобождается независимо от выхода из блока. В Java синхронизированный блок получит блокировку в начале (ждать, пока оно не станет доступным), и оставить замок, когда Программа покидает блок (по тем или иным причинам).

1 голос
/ 16 марта 2011

Синхронизация в java (технически) не об отказе других потоков в доступе к объекту, а об обеспечении уникального использования его (одновременно) между потоками, использующими блокировки синхронизацииТаким образом, T2 может получить доступ к объекту, пока T1 имеет блокировку синхронизации, но не сможет получить блокировку синхронизации, пока T1 не снимет ее.

1 голос
/ 16 марта 2011

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

2) Это частично зависит от используемой схемы синхронизации и желаемой семантики. При стандартном ключевом слове synchronized T2 будет блокироваться на неопределенный срок до тех пор, пока T1 не освободит монитор, после чего T2 получит монитор и продолжит логику внутри синхронизированного блока.

Если вы хотите более детальный контроль над поведением, когда утверждается блокировка, вы можете использовать явные Lock объекты. Они предлагают tryLock методы (как с тайм-аутом, так и с немедленным возвратом), которые возвращают true или false в зависимости от того, может ли быть получена блокировка. Таким образом, вы можете затем проверить возвращаемое значение и предпринять любое действие, которое вам нравится, если блокировка не была получена немедленно (например, регистрация функции обратного вызова, увеличение счетчика и предоставление обратной связи пользователю перед повторной попыткой и т. Д.).

Тем не менее, эта пользовательская реакция редко необходима и значительно увеличивает сложность вашего кода блокировки, не говоря уже о большой вероятности ошибок, если вы забудете всегда снимать блокировку в блоке finally тогда и только тогда, когда она была успешное получение и т. д. Как правило, просто используйте synchronized, если / пока не покажете, что оно обеспечивает существенное узкое место для требуемой пропускной способности вашего приложения.

1 голос
/ 16 марта 2011

Вы synchronize (блокировка), когда несколько потоков будут иметь доступ к чему-либо.

Второй поток будет блокироваться, пока первый поток не снимет блокировку (выйдет из синхронизированного блока)

Более детальное управление можно получить, используя java.util.concurrent.locks и используя неблокирующие проверки, если вы не хотите, чтобы потоки блокировались.

1 голос
/ 16 марта 2011

Я должен заблокировать массив, пока T1 не закончится, используя элемент, верно?

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

что должен делать Т2

Посмотрите массив, затем прочитайте значение. В настоящее время вы знаете, что никто не может изменить его. При использовании таких блокировок, как monitors, очередь автоматически сохраняется системой. Следовательно, если T2 попытается получить доступ к объекту, заблокированному T1, он будет блокироваться (зависать), пока T1 не снимет блокировку.

Пример кода:

private Obect[] array;
private static final Object lockObject = new Object();

public void modifyObject() {
    synchronized(lockObject) {
       // read or modify the objects
    }
}

Технически вы также можете синхронизироваться с самим массивом.

...