Java. Как правильно синхронизировать методы считывания и методы set?

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

class Doggie {
    private String name;
    private int    age;

    public void setName(String name) { this.name = name; }
    public String getName() { return this.name; }
    public void setAge(int age) { this.age = age; }
    public int getAge() { return this.age; }

}

Вопросы:

  • Не return и присвоение атомарные операции в Java?
  • Так как свойства не могли бы обязательно быть взаимосвязаны, не всегда имеет смысл синхронизироваться с той же блокировкой. Как организовать структуру блокировки?
  • Лучше пойти с внутренней блокировкой или частным Объектным шаблоном блокировки?
10
задан Jake 19 June 2010 в 21:51
поделиться

5 ответов

  • Разве в Java не являются атомарными операциями возврата и присваивания?

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

  • Когда операции чтения и записи выполняются в одном потоке, при чтении гарантированно обнаруживается более ранняя запись.

  • Когда операции чтения и записи выполняются в разных потоках, при чтении гарантируется только ранняя запись, если два потока синхронизируются правильно ... или если атрибут объявлен как volatile .

Обратите внимание, что примитивные блокировки / мьютексы - не единственный способ синхронизации.

  • Поскольку свойства не обязательно могут быть взаимосвязаны, не всегда имеет смысл синхронизировать с одной и той же блокировкой. Как организовать структуру блокировок?

Имеет смысл использовать несколько блокировок, если (и только если) вероятен конфликт блокировок. В вашем примере конкуренция за блокировку может стать проблемой только в том случае, если некоторый экземпляр Doggie получает очень высокую скорость операций получения и / или установки.

  • Что лучше: внутренняя блокировка или шаблон блокировки частного объекта?

Это зависит от обстоятельств.Если ваше приложение будет использовать примитивную блокировку объекта Doggie , то вы можете получить конфликт блокировок или даже непреднамеренную блокировку операций get и set. В этом случае рекомендуется использовать частную блокировку. В противном случае личная блокировка - это ненужные накладные расходы.

10
ответ дан 3 December 2019 в 20:02
поделиться

В вашем примере требуется неизменяемый объект. http://java.sun.com/docs/books/tutorial/essential/concurrency/imstrat.html

5
ответ дан 3 December 2019 в 20:02
поделиться

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

Лично я бы использовал единственный частный замок, пока не увидел никаких доказательств того, что это было узкое место. Я бы посоветовал не блокировать "this", так как другой код тоже может заблокировать его. Если вы единственный код, который знает о замке, вам будет труднее получить помехи. Сказав это, если вызывающие абоненты хотят атомарно изменить более одного свойства, вы можете выставить блокировку через свойство.

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

3
ответ дан 3 December 2019 в 20:02
поделиться
  • Это атомарные операции, но представьте сценарий, в котором два клиента пытаются получить и установить часть данных одновременно. Нет никакой гарантии, в каком порядке будут вызываться те или иные операции, что может сильно повлиять на результаты работы вашего приложения. (Классический пример - денежные транзакции.)
  • Синхронизация с одной и той же блокировкой может иметь смысл, а может и не иметь - это зависит от вашего приложения. Однако, как правило, не стоит блокировать весь объект, если в этом нет необходимости.
  • Как сказал Джон, начните с единственной, частной блокировки и двигайтесь дальше в зависимости от результатов.
1
ответ дан 3 December 2019 в 20:02
поделиться

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

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

0
ответ дан 3 December 2019 в 20:02
поделиться
Другие вопросы по тегам:

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