Java распараллеливает синхронизацию

В классе ниже, метод getIt() ориентированный на многопотоковое исполнение и почему?

public class X { 
  private long myVar; 
  public void setIt(long  var){ 
    myVar = var; 
   }  
   public long getIt() { 
     return myVar; 
  } 
}
14
задан Balder 1 April 2014 в 13:41
поделиться

8 ответов

Это не является потокобезопасным. Переменные типа long и double в Java рассматриваются как две отдельные 32-битные переменные. Один поток может вести запись и записать половину значения, когда другой поток считывает обе половины. В этой ситуации читатель увидел бы значение, которое никогда не должно было существовать.

Чтобы сделать это потокобезопасным, вы можете либо объявить myVar как volatile (Java 1.5 или более поздняя версия), либо сделать setIt и getIt синхронизированными.

Обратите внимание, что даже если myVar был 32-битным int, вы все равно можете столкнуться с проблемами потоков, когда один поток может читать устаревшее значение, которое другой поток изменил. Это может произойти из-за того, что значение было кэшировано процессором. Чтобы решить эту проблему, вам снова нужно объявить myVar как volatile (Java 1.5 или более поздняя версия) или сделать оба setIt и getIt синхронизированными.

Стоит также отметить, что если вы используете результат getIt в последующем вызове setIt, например, x.setIt(x. getIt() * 2), то вы, вероятно, захотите синхронизировать оба вызова:

synchronized(x)
{
  x.setIt(x.getIt() * 2);
}

Без дополнительной синхронизации другой поток может изменить значение между вызовами getIt и setIt, в результате чего значение другого потока будет потеряно.

22
ответ дан 1 December 2019 в 07:12
поделиться

Нет, это не так. По крайней мере, не на платформах, где отсутствует атомарный доступ к 64-битной памяти.

Предположим, что поток A вызывает setIt , копирует 32 бита в память, где находится значение поддержки, а затем предварительно очищается, прежде чем он сможет скопировать остальные 32 бита.

Затем поток B вызывает getIt .

6
ответ дан 1 December 2019 в 07:12
поделиться

Это не является потокобезопасным. Даже если ваша платформа гарантирует атомарную запись long , отсутствие synchronized делает возможным, что один поток вызывает setIt () и даже после того, как этот вызов завершил его возможно, что другой поток может вызвать getIt () , и этот вызов может вернуть старое значение myVar .

Ключевое слово synchronized делает больше, чем монопольный доступ одного потока к блоку или методу. Это также гарантирует, что второй поток будет проинформирован об изменении переменной.

Таким образом, вы должны либо пометить оба метода как синхронизированные , либо отметить элемент myVar как volatile .

Здесь есть очень хорошее объяснение синхронизации :

Атомарные действия не могут чередоваться, поэтому их можно использовать, не опасаясь вмешательства потоков. Однако это не устраняет всю необходимость синхронизировать атомарные действия, потому что ошибки согласованности памяти все еще возможны. Использование изменчивых переменных снижает риск ошибок непротиворечивости памяти, потому что любая запись в изменчивую переменную устанавливает связь «произошло раньше» с последующими чтениями той же переменной. Это означает, что изменения в изменчивой переменной всегда видны другим потокам. Более того, это также означает, что, когда поток читает изменчивую переменную, он видит не только последнее изменение изменчивой переменной, но и побочные эффекты кода, вызвавшего это изменение.

9
ответ дан 1 December 2019 в 07:12
поделиться

Нет, это не так, потому что longs не атомарны в java, поэтому один поток мог записать 32 бита long в метод setIt, а затем getIt мог прочитать значение, а затем setIt мог установить другие 32 бита.

В итоге getIt возвращает значение, которое никогда не было действительным.

3
ответ дан 1 December 2019 в 07:12
поделиться

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

  • сделать myVar конечным (но тогда вы не сможете его мутировать)
  • сделать myVar волатильным
  • использовать synchronized для доступа к myVar
0
ответ дан 1 December 2019 в 07:12
поделиться

Это должно быть, и обычно так и есть, но не гарантированно поточно-ориентированная. Могут быть проблемы с разными ядрами, имеющими разные версии в кеше ЦП, или с тем, что хранилище / извлечение не является атомарным для всех архитектур. Используйте класс AtomicLong .

2
ответ дан 1 December 2019 в 07:12
поделиться

Поскольку это метод только для чтения. Вы должны синхронизировать метод set.

EDIT : Я понял, почему метод get также должен быть синхронизирован. Хорошая работа по объяснению Фила Росса.

-4
ответ дан 1 December 2019 в 07:12
поделиться

Может быть глупо, но попробуйте ввести только «myscript.py» в cmd.exe, если вы находитесь в Windows. Я заметил, что в Windows не нужно вводить «python» перед именем сценария. Это, конечно, для стандартной установки CPython в Windows.

-121--4817465-

Какая часть приложения разрывается? Пользовательский интерфейс или бизнес-логика

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

-121--4012934-

AFAIK, современные JVM больше не разделяются на длинные и двойные операции. Я не знаю ни одной ссылки, которая утверждает, что это все еще проблема. Например, см. AtomicLong, который не использует синхронизацию в JVM Sun.

Если вы хотите быть уверены, что это не проблема, то вы можете использовать синхронизацию как get (), так и set (). Однако если вы выполняете такую операцию, как add, т.е. set (get () + 1), то эта синхронизация покупает вам мало, вам все равно придется синхронизировать объект для всей операции. (Лучший способ обойти это - использовать одну операцию для добавления (n), которая синхронизирована)

Однако лучшим решением является использование AtomicLong. Это поддерживает атомарные операции, такие как получение, установка и добавление, и не использует синхронизацию.

0
ответ дан 1 December 2019 в 07:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: