Если использовать аналогию: объект подобен большому дому, дверь которого всегда открыта. В доме много комнат (так называемых приемов). Эти комнаты либо заперты (синхронизированный метод), либо разблокированы (обычный метод). У двери комнаты есть ключ. Этот ключ может открыть все запертые комнаты. Кроме того, я сравниваю все потоки, желающие вызвать методы этого объекта, с людьми, желающими войти в определенную комнату в этом доме. Вот и все, давайте посмотрим, как эти вещи работают друг с другом.
Здесь мы сначала уточним наши предпосылки. У объекта есть хотя бы один синхронизированный метод, иначе этот ключ не имеет смысла. Конечно, такой нашей темы не будет.
Человек хочет войти в запертую комнату. Он подходит к двери дома и видит там ключ (указывающий, что никто больше не хочет пользоваться запертой комнатой). Поэтому он поднялся, взял ключи и воспользовался комнатами, как планировал. Обратите внимание, что он возвращает ключ сразу после каждого использования запертой комнаты. Даже если он захочет воспользоваться двумя запертыми комнатами подряд, ему придется вернуть ключ и получить его обратно между ними.
Поэтому принцип использования ключей в обычных обстоятельствах таков: «Одалживайте их по мере использования и возвращайте, как только воспользуетесь».
В настоящее время другие люди могут использовать разблокированные комнаты без ограничений. Один человек может использовать одну комнату, или два человека могут использовать одну комнату. Ограничений нет. Но если кто-то хочет войти в запертую комнату, ему придется подбежать к двери и посмотреть. Если у вас есть ключ, вы, конечно, можете взять его и уйти. Если у вас нет ключа, вам остается только подождать.
Если ключ ждут многие люди, кто получит его первым, когда ключ будет возвращен? Не гарантировано. Как и в случае с парнем из предыдущего примера, который хочет использовать две запертые комнаты подряд, если есть другие люди, ожидающие ключа, когда он возвращает ключ, нет никакой гарантии, что этот парень сможет получить его снова. (В спецификации JAVA во многих местах четко указано, что нет никаких гарантий, например, сколько времени потребуется Thread.sleep(), чтобы вернуться к работе после отдыха, какой поток с тем же приоритетом будет выполнен первым и когда блокировка доступа к объекту снята, несколько потоков в пуле ожидания получат объект. Какой поток получит его первым? И т. д. Я думаю, что окончательное решение остается за JVM. Причина отсутствия гарантий заключается в том, что, когда JVM принимает вышеуказанное решение, она выносит суждение не просто на основе одного условия, а на основе множества условий. множество условий оценки. Если вы их произнесете, это может повлиять на JAVA. Возможно, это связано с защитой интеллектуальной собственности. Компания SUN не дала никаких гарантий, и это понятно. Но я считаю, что эти неопределенности не являются полностью неопределенными, поскольку сам компьютер работает в соответствии с инструкциями. Даже, казалось бы, случайные явления на самом деле являются. Есть правила, которые нужно найти. Любой, кто изучал компьютеры, знает, что научное название случайных чисел в компьютерах — это псевдослучайные числа, которые записываются людьми с использованием определенного метода. Кроме того, это может быть потому, что они тоже хотят этого. конечно, это очень хлопотно и не имеет особого смысла, так что, если вы не уверены, просто не будьте уверены.)
Давайте еще раз посмотрим на синхронизированные блоки кода. Он немного отличается от метода синхронизации.
1. По размеру синхронизированные блоки кода меньше синхронизированных методов. Вы можете думать о синхронизированном блоке кода как о пространстве в незапертой комнате, отделенном заблокированным экраном.
2. Блок кода синхронизации также может вручную указать ключ другого объекта. Это все равно, что указать, каким ключом можно открыть замок этого экрана. Вы можете использовать ключ этого дома, а также указать ключ другого дома, чтобы открыть его. В этом случае вам придется бежать к другому дому. чтобы открыть замок. Получите этот ключ и используйте этот ключ от дома, чтобы открыть заблокированный экран этого дома.
Помните, что полученный вами ключ от другого дома не мешает другим людям входить в незапертые комнаты этого дома.
Зачем использовать синхронизированные блоки кода? Я думаю, должно быть так: Прежде всего, на эффективность работы влияет часть синхронизации программы, и метод обычно сначала создает какие-то локальные переменные, а затем выполняет над этими переменными какие-то операции, такие как вычисления, отображение и т.д. ; и синхронизация Чем больше кода, тем серьезнее влияние на эффективность. Поэтому мы обычно стараемся свести масштабы его воздействия к минимуму. Как это сделать? Синхронизированные блоки кода. Мы синхронизируем только те части метода, которые должны быть синхронизированы, например операции.
Кроме того, блок кода синхронизации может указывать ключ. Эта функция имеет дополнительное преимущество, заключающееся в том, что ключ объекта занимает определенный период времени. Помните, что я говорил ранее о принципах использования ключей в нормальных обстоятельствах. Это не обычные обстоятельства. Полученный вами ключ не возвращается навсегда, а возвращается только при выходе из синхронизированного блока кода.
Давайте воспользуемся аналогией с парнем, который хотел использовать две запертые комнаты подряд. Как я могу продолжать использовать другую комнату после использования одной комнаты? Используйте синхронизированные блоки кода. Сначала создайте еще один поток, создайте блок кода синхронизации и направьте замок этого блока кода на ключ от дома. Тогда начните эту тему. Если вы можете получить ключ от дома при входе в этот кодовый блок, вы можете хранить его до тех пор, пока не выйдете из этого кодового блока. Другими словами, можно хоть пройти все запертые комнаты в этой комнате, и даже поспать (10*60*1000), но у двери все равно 1000 потоков ждут ключа. Это довольно приятно.
Давайте поговорим о корреляции между методом Sleep() и ключом. Если поток вынужден перейти в режим сна() после получения ключа и не завершил синхронизацию содержимого, ключ все равно останется там. Ключ не будет возвращен до тех пор, пока он не будет запущен снова и все содержимое синхронизации не будет завершено. Помните, парень просто устал от работы и пошел отдохнуть. Он не успел сделать то, что хотел. Чтобы посторонние не могли войти в комнату и не навести там беспорядок, ему приходилось носить единственный ключ при себе, даже когда он спал.
Наконец, кто-то может спросить, почему нам нужен один ключ для открытия каждой двери, а не один ключ для каждой двери? Я думаю, что это чисто вопрос сложности. Один ключ от одной двери, конечно, безопаснее, но это повлечет за собой массу проблем. Генерация, хранение, приобретение, возврат ключей и т.д. Его сложность может увеличиваться в геометрической прогрессии по мере увеличения количества методов синхронизации, что серьезно влияет на эффективность. Это можно рассматривать как вопрос компромисса. Как нежелательно сильно снижать эффективность ради того, чтобы хоть немного повысить безопасность.