2013-12-11 2 views
4

Возможно, это очень глупый вопрос. Просто хотел подтвердить свое понимание.Необходимость синхронизации в геттерах и сеттерах

class Test 
{ 
     private volatile String id; 

     public void setID(String id) 
     { 
      this.id = id; 
     } 

     public String getID() 
     { 
      return id; 
     } 
} 

Допустим, что к объекту вышеуказанного класса можно получить доступ по нескольким потокам. Мое понимание заключается в том, что в случае простых getter и seters, как описано выше (простую инициализацию), мне не нужно синхронизировать эти методы, правильно?
Я думаю, что volatile необходим, поскольку в противном случае значение id может устаревать иначе в разных потоках.
Итак, может ли кто-нибудь увидеть какую-либо проблему, если у нас нет таких методов, как синхронизировано?

+0

Может быть, этот вопрос поможет вам: http://stackoverflow.com/questions/15828067/java-synchronized-keyword-needed-on-primitive-getter-setter-method – pad

+0

Нет, вы должны синхронизировать его в вашем методе также –

+0

для этого требуется синхронизация для ключевого слова volatile, без него, если POJO не является одиночным или разделяется через все потоки, ему не потребуется синхронизация. – RamonBoza

ответ

6

Я понимаю, что в случае простых геттеров и сеттеров, подобных описанным выше (выполняющих простую инициализацию), мне не нужно синхронизировать эти методы, правильно?

Правильно, потому что то, что они получают и устанавливают (ссылка на объект), обрабатывается JVM атомарно.

Ответ будет «Нет, вы сделать нужна синхронизация», если вы использовали long или double и вы не были отмечены его volatile.

Оба аспекта этого покрыты в JLS, §17.7:

17,7. Неатомная обработка двойных и длинных

Для целей модели памяти языка программирования Java одна запись в энергонезависимое длинное или двойное значение рассматривается как две отдельные записи: по одной на каждую 32-битную половину , Это может привести к ситуации, когда поток видит первые 32 бита 64-битного значения из одной записи, а второй 32 бита из другой записи.

Запись и чтение изменчивых длинных и двойных значений всегда являются атомарными.

Запись и чтение ссылок всегда являются атомами, независимо от того, реализованы ли они как 32-разрядные или 64-битные значения.

+0

просто '' длинные' 'ы? или это относится также к другим примитивам? –

+0

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

+0

@snow_leopard: Не для ссылки на объект, нет; вы бы использовали 'long' или' double'. (См. Обновленный ответ - навсегда уладил, глупая широкополосная связь снизилась. Я понял, что вы бы поставили 'volatile', но я этого не видел.' Volatile' обращается к 'long' и' double'. Обновленный ответ должен быть более ясным.) –

1

Если вы находитесь в округе multi-threaded. несколько потоков могут получить доступ к вашим данным. Значение чтения (get) прекрасно. Но подумайте о записи (set), тогда ваши данные станут несовместимыми. Поэтому у вас есть Synchronized.

+0

Да, я забыл добавить, что в моем случае только один поток фактически установит ID, и несколько потоков смогут прочитать это значение. –

+0

@Ruchira: 'synchronized' здесь не имеет никакого значения, значение устанавливается атомарно JVM без него. –

+0

@ T.J.Crowder Если у нас есть «синхронизированный» сеттер, только один поток сможет установить значение за раз, в то время как другой будет ждать –

0
My understanding is that in case of simple getter and setters like above 
(doing simple initialization), I do not need to make these methods 
synchronized, correct ? 

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

Однако возможно, что одна нить входит в функцию public String getID(). В этот момент другой поток может очень хорошо изменить значение переменной, выполнив метод public void setID(String id). 1-й поток увидит это измененное значение.

Так что не путайте между использованием атомных переменных и функциями синхронизации.

+0

Хотя верно, что без синхронизации Thread A может войти в 'getID', тогда Thread B может изменить значение до того, как Thread A прочитает его, сделав Thread A возвращенным новым значением, а не старым, он вообще не будет иметь никаких рабочих различий, поскольку все 'getID' does считывается и возвращает значение. Это гонка в любом случае. Единственная причина для синхронизации * этих конкретных * геттеров и сеттеров - это целостность данных (обеспечение того, что значения читаются/записываются атомарно, поэтому мы не получаем половину старого значения и половину нового), и в этом случае это не нужно , –

1

Вам не нужно синхронизировать любые из этих функций и не использовать ключевое слово volatile, поскольку ссылки на задания всегда являются атомарными. Однако есть и другие проблемы, возникающие в результате несинхронизации/нелетуляции.

Первое: что Поток А читает через GetId не может быть, что Thread B писал через SETID, так как Thread А был слишком рано или ...

Второе: Автор А была на время, но из-за отсутствия волатильна, вместо реальной стоимости он считывал переменную с кеш-кешем.

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

Тема A:

myId.setId(3); 
idSet = true; 

Тема B:

if (idSet) { 
    accessData(myId.getId()); 
} 

Это выглядит правильно - и это вроде есть - но то, что может произойти во время этапа оптимизации JVM, что сначала выполняется idSet = true, а затем myId.setId(3). Поэтому в худшем случае Thread B преуспевает в условии if, но затем читает неправильное значение. Маркировка id как volatile решит эту проблему, так как она гарантирует, что всякий раз, когда изменяется id, все, что произошло до.

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

Смежные вопросы