Если у меня есть 2 синхронизированных метода в одном и том же классе, но каждый имеет доступ к разным переменным, могут ли 2 потока получить доступ к этим двум методам одновременно? Происходит ли блокировка объекта или он становится таким же специфичным, как переменные внутри синхронизированного метода?
Пример:
class X {
private int a;
private int b;
public synchronized void addA(){
a++;
}
public synchronized void addB(){
b++;
}
}
Могут ли 2 потока получить доступ к одному и тому же экземпляру класса X x.addA(
и x.addB()
одновременно?
synchronized (this)
блока вокруг тела метода. Объект «this» не блокируется, скорее объект «this» используется как мьютекс, и тело не может выполняться одновременно с другими разделами кода, также синхронизированными с «this». Это не влияет на другие поля / методы «this», которые не синхронизированы.a
иb
были объектами, например,Integer
s, вы выполняли синхронизацию на экземплярах, которые вы заменяли другими объектами при применении++
оператора.Синхронизация по объявлению метода является синтаксическим сахаром для этого:
По статическому методу это синтаксический сахар для этого:
Я думаю, что если бы Java-дизайнеры знали тогда, что теперь понимают в отношении синхронизации, они бы не добавили синтаксический сахар, поскольку это чаще всего приводит к плохим реализациям параллелизма.
источник
Из «Учебников Java ™» по синхронизированным методам :
Из «Учебников Java ™» по синхронизированным блокам :
(Акцент мой)
Предположим, у вас есть 2 не перемежающиеся переменные. Таким образом, вы хотите получить доступ к каждому из разных потоков одновременно. Вы должны определить блокировку не для самого класса объекта, а для класса Object, как показано ниже (пример из второй ссылки Oracle):
источник
Доступ к блокировке есть на объекте, а не на методе. Какие переменные доступны в методе, не имеет значения.
Добавление «synchronized» в метод означает, что поток, выполняющий код, должен получить блокировку объекта перед продолжением. Добавление «статической синхронизации» означает, что поток, выполняющий код, должен получить блокировку объекта класса, прежде чем продолжить. В качестве альтернативы вы можете заключить код в блок следующим образом:
так что вы можете указать объект, чья блокировка должна быть получена.
Если вы хотите избежать блокировки на содержащем объекте, вы можете выбрать между:
источник
Из документации оракула ссылка
Синхронизация методов имеет два эффекта:
Взгляните на эту страницу документации, чтобы понять внутренние блокировки и поведение блокировки.
Это ответит на ваш вопрос: для одного и того же объекта x нельзя вызывать x.addA () и x.addB () одновременно, когда выполняется один из синхронизированных методов.
источник
Если у вас есть какие-то методы, которые не синхронизированы и обращаются к переменным экземпляра и изменяют их. В вашем примере:
любое количество потоков может обращаться к этим несинхронизированным методам одновременно, когда другой поток находится в синхронизированном методе того же объекта и может вносить изменения в переменные экземпляра. Например:
Необходимо избегать сценария, когда несинхронизированные методы обращаются к переменным экземпляра и изменяют его, иначе нет смысла использовать синхронизированные методы.
В приведенном ниже сценарии:
Только один из потоков может быть либо в методе addA, либо в addB, но в то же время любое количество потоков может войти в метод changeState. Никакие два потока не могут войти в addA и addB одновременно (из-за блокировки уровня объекта), но в то же время любое количество потоков может войти в changeState.
источник
Вы можете сделать что-то вроде следующего. В этом случае вы используете синхронизацию a и b для синхронизации вместо блокировки «this». Мы не можем использовать int, потому что примитивные значения не имеют блокировок, поэтому мы используем Integer.
источник
Да, он будет блокировать другой метод , потому что синхронизирован метод применяется к ВСЕМУ объекту класса , как заостренные .... но в любом случае он будет блокировать другие выполнения потока только при выполнении суммы в любом методе Адда или ADDB он поступает, потому что , когда он закончить ... один поток освободит объект, а другой поток получит доступ к другому методу и так далее, отлично работающему.
Я имею в виду, что «синхронизированный» создан именно для того, чтобы блокировать другой поток от доступа к другому во время выполнения определенного кода. НАКОНЕЦ, ЭТОТ КОДЕКС БУДЕТ РАБОТАТЬ В КАЧЕСТВЕ.
И последнее замечание: если есть переменные 'a' и 'b', а не просто уникальная переменная 'a' или какое-либо другое имя, нет необходимости синхронизировать эти методы, потому что это совершенно безопасно для доступа к другим var (Другая память расположение).
Будет работать так же
источник
Этот пример (хотя и не очень) может дать более глубокое понимание механизма блокировки. Если incrementA будет синхронизирована , и incrementB это не синхронизированы , то incrementB будет выполняться как можно быстрее, но если incrementB также синхронизированы , то он должен «ждать» incrementA до конца, до того incrementB может делать свою работу.
Оба метода вызываются для одного экземпляра - объекта, в данном примере это: job , а 'конкурирующими' потоками являются aThread и main. .
Попробуйте использовать « synchronized » в incrementB и без него, и вы увидите разные результаты. Если incrementB также « синхронизирован », то он должен ждать завершения incrementA (). Запустите несколько раз каждый вариант.
источник
В синхронизации Java, если поток хочет войти в метод синхронизации, он получит блокировку для всех синхронизированных методов этого объекта, а не только для одного синхронизированного метода, который использует поток. Таким образом, поток, выполняющий addA (), получит блокировку для addA () и addB (), поскольку оба синхронизированы. Так что другие потоки с тем же объектом не могут выполнить addB ().
источник
Это может не работать, так как бокс и автобокс от Integer до int и наоборот зависит от JVM, и существует высокая вероятность того, что два разных числа могут быть хэшированы на один и тот же адрес, если они находятся между -128 и 127.
источник