Какова цель указания объекта для блокировки?
Часто синхронизировать проще на this
или Class
(для статических методов). Но есть случаи, когда вам нужно будет синхронизировать определенный объект вместо неявной блокировки (this
). К таким случаям относятся:
- Вы хотите синхронизировать доступ к примитивам без использования
this
. Вы можете синхронизировать только на Object
s, поскольку каждый Object
связан с неявным монитором в Java. Примитивы не имеют таких неявных мониторов, и поэтому вам нужно использовать объект блокировки. Использование классов-обёрток плохой и неправильный выбор, особенно если вы в итоге измените объект блокировки в защищенном блоке .
- Вы хотите выполнить синхронизацию на объекте, который фактически защищает критическую секцию, когда синхронизация на
this
не будет гарантировать безопасность потока. Например, если вы синхронизируете доступ к экземпляру ArrayList
, совместно используемому для экземпляров класса A
, то синхронизация для экземпляра A
бесполезна. Поток может создать новый экземпляр A
и получить доступ к списку, в то время как другой поток изменяет его. Если вы используете другую блокировку, за которую должны бороться все потоки, вы можете защитить список; эта блокировка может быть привязана к A.class
, но это может быть любой объект, который будет предоставлять те же гарантии.
- Вы хотите выполнить разбиение блокировок, чтобы гарантировать, что различные охраняемые блоки защищены разными блокировками вместо одной и той же блокировки. Другими словами, если потокобезопасно разрешать различным потокам получать разные блокировки для доступа к разным критическим секциям, тогда вы можете иметь разные блокировки для каждой критической секции.
Ниже приведен пример использования разделенной блокировки:
private Object method1Lock = new Object();
private Object method2Lock = new Object();
public void method1(){
synchronized(method1Lock){
....
}
}
public void method2(){
synchronized(method2Lock){
....
}
}
Вы бы использовали разделенные блокировки, если вы можете гарантировать, что одновременное выполнение method1
и method2
не нарушает инварианты класса. Таким образом, вы можете повысить производительность потоков, которым необходим доступ к одному и тому же объекту, но которые будут вызывать разные методы.
На ваш другой вопрос,
Например, во втором примере смогут ли потоки все еще выполнять код внутри синхронизированного блока, поскольку блокировка не связана с экземпляром this?
Во втором примере любой поток, входящий в защищенную область, должен получить блокировку, связанную с aStringBufferObject
. Если другой поток удерживает эту блокировку, то текущий поток не будет продолжать дальше. Когда вы указываете this
, тогда поток должен получить блокировку, связанную с текущим объектом. В обоих случаях поток должен получить блокировку; примеры отличаются только для объекта, который используется в качестве блокировки.