2012-03-21 2 views
0

У меня есть многопоточная программа, и мне интересно, какой из способов использования «синхронизирован» правильный.Java «synchronized» в классе объектов или в вызывающем классе

Способ 1: У меня есть объект класса (который будет передан в нескольких потоков), называемый МойКлассом, внутри него:

public synchronized void set(String name) { 
    this.name = name; 
} 

Путь 2: У меня же класс, но не имеющие «синхронизирован "в своем множестве метод:

public void set(String name) { 
    this.name = name; 
} 

И абонент будет сделать это:

MyClass myclass = new MyClass(); 
synchronized(myclass) { 
    myclass.set("myclass"); 
} 

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

ответ

6

Синхронизировать по методу:

  • Вы делаете это в одном месте,
  • Вызывающие не придется беспокоиться о синхронизации,
  • Вы не дублировать код везде, где вам нужно позвонить
  • Самое главное - если звонящий опускаем Синхронизировать, это не будет работать

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

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

+1

Я согласен с этим.Чтобы написать потокобезопасную программу, суть решения - это «контекст» вашего дизайна. «Дизайн» - это правильный выбор из нескольких тактик. –

0

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

1

Первый вариант - это правильная версия в целом.

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

Теперь технически в примере, который вы указали, нет никакого способа, чтобы два потока могли попасть в проблему, потому что, если один поток создает экземпляр и вызывает set(). Нет другого способа, которым поток мог иметь доступ к этому экземпляру. Поэтому никогда не будет споров о блокировке. Просто вы знаете, как создание объектов влияет на многопоточные программы. Помните, что два потока должны ОБРАТИТЬ общую ссылку на экземпляр, который они намереваются изменить для любых проблем с потоками, которые могут быть проблемой. Если они никогда не разделяют общую ссылку, нет проблем с безопасностью.

0

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

Замок метода. Помните, что вам также нужно синхронизировать свой метод get, или он может отражать несогласованное состояние объекта, потому что если он не , он не будет проверять блокировку и может завершиться параллельно, в то время как блокировка объекта удерживается в другом потоке ,

0

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

Is there an advantage to use a Synchronized Method instead of a Synchronized Block?

0

Я буду голосовать за второй вариант. Классы вообще не должны быть потокобезопасными (и поэтому не должны быть внутренне синхронизированы). Безопасность требует времени и часто не нужна. Кроме того, вы часто получаете такие ситуации, как: if (list.isEmpty()) list.add(filler);. Если оба метода синхронизируются внутри, это не делает ничего хорошего. Список может быть пустым при первом вызове и иметь 1 000 000 записей при вызове add. Весь оператор должен быть синхронизирован, чтобы быть полезным.

В целом, для каждого класса вам необходимо решить, является ли он потокобезопасным или нет. Те, что не будут, будут быстрее и могут быть сделаны потокобезопасными вызывающим абонентом, которому, как и в приведенном выше экземпляре, может понадобиться некоторая гибкость в том, как они идут по нему. Кроме того, есть умные способы избежать любой необходимости синхронизации, например, ссылаться на класс из одного потока. Большинство классов Java Collections Framework не являются и не должны быть потокобезопасными. Безопасность резьбы обычно должна обрабатываться на высоком уровне, а не на низком уровне.

Время от времени вы получаете класс низкого уровня, который должен обрабатывать много потоков трафика, а затем вам нужен do нужен класс, который является потокобезопасным. Моим любимым примером является JavaConcurrentSkipListMap, который выполняет ту же работу, что и TreeMap. Я использую TreeMap 100 раз для каждого использования JCSLM, но когда мне это нужно, это спасатель. (Без этого я бы застрял с Java 1.4.)

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

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

У меня есть Удача, в редких случаях, просто синхронизация каждого метода в классе. И я могу (намеренно) заблокировать все это просто путем синхронизации с классом. Это просто и безопасно, и не вредит, если класс легко используется. Но я иногда ошибаюсь в отношении использования класса и должен отказаться от него, когда моя программа зависает, используя только 2% процессора, несмотря на 4 гиперпотоковых ядра.

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

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