В примере methodA и methodB являются методами экземпляра (в отличие от статических методов). Установка synchronized
метода экземпляра означает, что поток должен получить блокировку («внутреннюю блокировку») для экземпляра объекта, к которому вызывается метод, прежде чем поток сможет начать выполнение любого кода в этом методе.
Если у вас есть два разных метода экземпляра, помеченных как синхронизированные, и разные потоки вызывают эти методы одновременно для одного и того же объекта, эти потоки будут бороться за одну и ту же блокировку. Как только один поток получает блокировку, все другие потоки закрываются от всех синхронизированных методов экземпляра этого объекта.
Чтобы два метода работали одновременно, они должны использовать разные блокировки, например:
class A {
private final Object lockA = new Object();
private final Object lockB = new Object();
public void methodA() {
synchronized(lockA) {
//method A
}
}
public void methodB() {
synchronized(lockB) {
//method B
}
}
}
где синтаксис синхронизированного блока позволяет указать конкретный объект, в котором исполняющий поток должен получить внутреннюю блокировку для входа в блок.
Важно понимать, что, несмотря на то, что мы помещаем ключевое слово «synchronized» в отдельные методы, основная концепция - это внутренняя блокировка за кулисами.
Вот как учебник Java описывает отношения:
Синхронизация строится вокруг внутренней сущности, известной как внутренняя блокировка или блокировка монитора. (Спецификация API часто именует эту сущность просто как «монитор».) Внутренние блокировки играют роль в обоих аспектах синхронизации: обеспечение исключительного доступа к состоянию объекта и установление отношений «до и после», которые важны для видимости.
Каждый объект имеет встроенную блокировку, связанную с ним. По соглашению поток, которому требуется исключительный и согласованный доступ к полям объекта, должен получить внутреннюю блокировку объекта перед тем, как получить к ним доступ, а затем снять внутреннюю блокировку, когда это будет сделано с ними. Говорят, что поток владеет внутренней блокировкой между моментом, когда он получил блокировку и снял ее. Пока потоку принадлежит внутренняя блокировка, никакой другой поток не может получить такую же блокировку. Другой поток заблокируется, когда попытается получить блокировку.
Целью блокировки является защита общих данных. Вы будете использовать отдельные блокировки, как показано в приведенном выше примере кода, только если каждая блокировка защищает разные элементы данных.