Что на самом деле означает встроенная блокировка для класса Java?
=================================================================

Чтобы правильно понять проблемы и решения для параллелизма в Java, я прошёл официальное руководство по Java. На одной из страниц они определили**Внутренние блокировки и синхронизация** [ссылка на сайт](https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html), На этой странице они говорят, что:

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

Также они упоминают в разделе**Блокировки в синхронизированных методах** тот:

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

Для меня это означает, что как только я вызову синхронизированный метод из одного из потоков, у меня будет внутренняя блокировка потока, и, поскольку

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

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

Так что просто повторить мой комментарий выше в качестве ответа. Внутренняя блокировка означает, что вам не нужно создавать объект для синхронизации ваших методов. Для сравнения вы можете использовать внешнюю блокировку, вызвав`synchronized(myLock) {...}`.

Это отрывок из книги[Java-параллелизм на практике](https://amzn.com/0321349601): «Тот факт, что каждый объект имеет встроенную блокировку, это просто удобство, так что вам не нужно явно создавать объекты блокировки»

Книга также говорит:

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

Но в сноске говорится:

[9] В ретроспективе это конструктивное решение, вероятно, было плохим: оно не только может сбить с толку, но и заставляет разработчиков JVM находить компромисс между размером объекта и производительностью блокировки.

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

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

Как[Брайан Гетц помещает в эту запись в блоге](https://www.ibm.com/developerworks/java/library/j-threads1/index.html):

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



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

Вы не можете звонить другим`synchronized` метод на том же объекте для блокировки уровня объекта, и вы не можете вызвать другой`static sysnchronized` метод в том же классе.

Но это не противоречит цели синхронизации.

Если вы будете следовать другой странице документации на[синхронизированный](https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html) методы:

Создание этих методов`synchronized` имеет два эффекта:

Во-первых, невозможно выполнить два вызова синхронизированных методов для одного и того же объекта. Когда один поток выполняет синхронизированный метод для объекта, все другие потоки, которые вызывают синхронизированные методы для того же блока объекта (приостанавливают выполнение), пока первый поток не завершится с объектом.Во-вторых, при выходе из синхронизированного метода он автоматически устанавливает отношение «до и после» с любым последующим вызовом синхронизированного метода для того же объекта. Это гарантирует, что изменения состояния объекта видны всем потокам.Если вы позволите два`synchronized` метод для параллельного запуска. вы будете обязаны получать ошибки несоответствия памяти на общих данных.

С другой стороны,[Замок](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html) обеспечивает лучшую альтернативу`synchronized` построить.

Связанный вопрос SE:

[Синхронизация против блокировки](https://stackoverflow.com/questions/4201713/synchronization-vs-lock/34267717?s=2|2.9259#34267717)



Неважно,`synchronized` Метод принадлежит к тому же классу или нет, имеет значение, если поток вызывающего метода получает блокировку или нет, если это так, то ему будет разрешено войти в критическую секцию, потому что блокировка`reentrant`.

Если бы это было не так, то рекурсивный вызов может привести к тупику,

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



Замки можно разделить на два класса - «входящие» и «не входящие». В Java «синхронизированный» базовая реализация интерфейса Lock (класс ReentrantLock), интерфейс ReadWriteLock (класс ReentrantReadWriteLock) - являются реентерабельными. Повторный вход означает - одна нить может снова и снова удерживать блокировку.



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



Блокировка может удерживаться только одним потоком за раз. Это не побеждает цель; тотявляется цель.

Потокимутuallyбывшийблокировать друг друга от одновременных действий в критических секциях, получая блокировку, илимьютекс. Это обеспечивает эффективную атомарность вокруг ряда отдельных действий, так что другие потоки никогда не видят промежуточные состояния, которые могут нарушать гарантии согласованности.



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

Внутренняя блокировка: просто представьте, что каждый объект в JVM имеет внутреннюю блокировку.`synchronized` Ключевое слово пытается получить блокировку целевого объекта. Всякий раз, когда вам`synchronized (a) { doSomething; }`что на самом деле происходит

замок в`a` приобретенкод внутри синхронизированного блока выполняется (`doSomething`)снять блокировку в`a`и я хочу, чтобы ты знал

концептуально так же, как

Хорошо, вернемся к вашему вопросу, самая большая проблема, imho, это:

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

это**неправильно**, Когда вы вызываете синхронизированный метод, вы**не** завладеть замком**нить**.

Вместо этого**нить** будет владеть внутренним замком**объект** это «владение» методом.

например в теме1 вы звонили`a.foo()`и предположим,`foo()` синхронизирован. thread1 собирается получить внутреннюю блокировку объекта`a` ссылаясь.

Точно так же, если`AClass.bar()` называется (и`bar` синхронизируется и статический метод), внутренний замок`AClass` Объект класса будет приобретен.