1) В основном да. Вам не нужно обязательно блокировать массив , вы можете заблокировать на более высоком уровне детализации (скажем, включающий класс, если бы он был закрытой переменной). Важно то, что ни одна часть кода не пытается изменить или прочитать из массива без удержания той же блокировки. Если это условие нарушается, это может привести к неопределенному поведению (включая, помимо прочего, просмотр старых значений, просмотр значений мусора, которые никогда не существовали, создание исключений и создание бесконечных циклов).
2) Это частично зависит от используемой схемы синхронизации и желаемой семантики. При стандартном ключевом слове synchronized
T2
будет блокироваться на неопределенный срок до тех пор, пока T1
не освободит монитор, после чего T2
получит монитор и продолжит логику внутри синхронизированного блока.
Если вы хотите более детальный контроль над поведением, когда утверждается блокировка, вы можете использовать явные Lock объекты. Они предлагают tryLock
методы (как с тайм-аутом, так и с немедленным возвратом), которые возвращают true
или false
в зависимости от того, может ли быть получена блокировка. Таким образом, вы можете затем проверить возвращаемое значение и предпринять любое действие, которое вам нравится, если блокировка не была получена немедленно (например, регистрация функции обратного вызова, увеличение счетчика и предоставление обратной связи пользователю перед повторной попыткой и т. Д.).
Тем не менее, эта пользовательская реакция редко необходима и значительно увеличивает сложность вашего кода блокировки, не говоря уже о большой вероятности ошибок, если вы забудете всегда снимать блокировку в блоке finally
тогда и только тогда, когда она была успешное получение и т. д. Как правило, просто используйте synchronized
, если / пока не покажете, что оно обеспечивает существенное узкое место для требуемой пропускной способности вашего приложения.