Допустимо всегда использовать «это» в качестве блокировки монитора?

Например, у меня есть класс с 2 счетчиками (в многопоточной среде):

public class MyClass {
  private int counter1;
  private int counter2;

  public synchronized void increment1() {
        counter1++;
  }

  public synchronized void increment2() {
        counter2++;
  }

}

Theres 2 increment operations not related with each other. But I use same object for lock (this).

Это правда, что если клиенты одновременно вызывают методы increment1() и increment2() , то вызов increment2 будет заблокирован до increment1 ( ) выпускает этот монитор?

Если это правда, означает ли это, что мне нужно предоставить разные блокировки монитора для каждой операции (по соображениям производительности)?

3
я снял его с момента добавления неправильного значения
добавлено автор dinesh707, источник
@ dinesh707 - Это полностью неверно. ОП имеет это право.
добавлено автор Brian Roach, источник
@ dinesh707, только если JVM определяет, что они не взаимодействуют. Если они взаимодействуют, они должны быть синхронизированы.
добавлено автор John Dvorak, источник

7 ответы

Правда, если клиенты одновременно вызывают методы increment1() и increment2 (), то приращение2 будет заблокировано до тех пор, пока increment1() не выпустит этот монитор?

Если их вызывают в одном экземпляре, то да.

Если это правда, означает ли это, что мне нужно предоставить различные блокировки монитора для каждой операции (по соображениям производительности)?

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

Я бы предпочел не синхронизировать этот по совершенно другим причинам. Уже достаточно сложно рассуждать о потоковой передаче, когда вы делаем все управляете, но когда вы не знаете всего, что может приобрести монитор, вы скрываетесь ни к чему. Когда вы синхронизируете этот , это означает, что любой другой код, который имеет ссылку на ваш объект, также может синхронизироваться на одном мониторе. Например, клиент может использовать:

synchronized (myClass) {
   //Do something entirely different
}

Это может привести к взаимоблокировкам, проблемам с производительностью, всем возможным вещам.

Если вместо этого вы используете поле private final в своем классе, а объект, созданный just , должен быть монитором, то вы знаете, что единственным кодом, приобретающим этот монитор, будет ваш код ,

12
добавлено

1) yes it's true that increment1() blocks increment2() and vice versa because they both are implicitly synchronizing on this

2) если вам нужна более высокая производительность, рассмотрите блокировку java.util.concurrent.atomic.AtomicInteger

  private AtomicInteger counter1 = new AtomicInteger();
  private AtomicInteger counter2 = new AtomicInteger();

  public void increment1() {
        counter1.getAndIncrement();
  }

  public void increment2() {
        counter2.getAndIncrement();
  }
5
добавлено

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

Если вы хотите синхронизировать только счетчик за раз, поэтому два потока не будут блокировать друг друга при доступе к различным переменным, вам нужно добавить два счетчика здесь в два синхронизированных блока и использовать разные переменные в качестве «блокировки» двух блоки.

2
добавлено
вы блокируете весь объект - это значит, что если я вызову длинный синхронизированный объект ob ob, то я не могу использовать этот объект до тех пор, пока синхронизированный метод не будет запущен?
добавлено автор MyTitle, источник
Вы можете использовать этот объект, но вы не можете выполнять monitor_enter на этом объекте как блокировку! Итак, еще один вызов на increment2 (также необходимо заблокировать «этот» объект), придется ждать.
добавлено автор StarPinkER, источник

Вы правы, это будет узким местом производительности, если вы используете тот же объект. Вы можете использовать разные блокировки для отдельного счетчика или использовать java.util.concurrent.atomic.AtomicInteger для параллельного счетчика.

Подобно:

public class Counter {
  private AtomicInteger count = new AtomicInteger(0);
  public void incrementCount() {
    count.incrementAndGet();
  }
  public int getCount() {
    return count.get();
  }
}
2
добавлено

Да, данный код идентичен следующему:

  public void increment1() {
        synchronized(this) {
             counter1++;
        }
  }

  public oid increment2() {
        synchronized(this) {
             counter2++;
        }
  }

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

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

1
добавлено

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

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

0
добавлено
pro.jvm
pro.jvm
3 503 участник(ов)

Сообщество разработчиков Java Scala Kotlin Groovy Clojure Чат для нач-их: @javastart Наш сайт: projvm.com projvm.ru Наш канал: @proJVM Вакансии: @jvmjobs Конфы: @jvmconf

Java & Co
Java & Co
2 370 участник(ов)

Можно обсуждать с матом и без всё, что касается жабы, вплоть до холиваров. НЕ ИМЕЕТ ОТНОШЕНИЯ К САЙТУ JAVARUSH.RU ПРАВИЛА - https://t.me/javarush/75723 Вакансии сюда - https://telegram.me/joinchat/B7IzvUCnfo6d8t3yIxKguQ По вопросам - @thedude

learn.java
learn.java
1 888 участник(ов)

Чат для начинающих и не только Статистика: https://combot.org/chat/-1001083535868 Основной чат - @jvmchat

Java Underground
Java Underground
169 участник(ов)

https://vk.com/javatutorial

Javanese Questions
Javanese Questions
109 участник(ов)

Чат предназначен для обмена знаниями строго в формате в вопрос-ответ. Тема — Java, Kotlin и Android. Вопрос должен быть предварительно прогуглен, понятно и грамотно сформулирован, помечен хэштегами. Ответ — тем более. Куски кода размером в несколько строк можно писать прямо здесь, для больших кусков кода стоит использовать http://gist.github.com/, http://pastebin.com/, https://codeshare.io/ или любой аналогичный сервис. В некоторых случаях можно прикреплять скриншоты. Стикеры и гифки запрещены. Дополнять и уточнять вопросы и ответы — редактированием исходного сообщения. Обсуждения должны приводить к редактированию вопроса/ответа и удаляться. По хештегам можно искать существующие вопросы и овтеты: #вопрос #ответ #git #generics #java #server #awt #javafx #swing #kotlin #anko #tornadofx #ktor #android #recyclerView #performance #arch #network #permissions #storage #async