Синхронизированные потоки и блокировки

Может кто-нибудь объяснить разницу между этими двумя примерами в контексте блокировки объекта:

public void method1(){
    synchronized(this){
        ....
    }
}

И

StringBuffer aStringBufferObject = new StringBuffer("A");

public void method2(){
    synchronized(aStringBufferObject){
        ....
    }
}

Я знаю, что первый пример получит блокировку экземпляра this, а второй получит блокировку экземпляра aStringBufferObject. Но я действительно не понимаю, каков эффект или разница между ними.

Например, во втором примере смогут ли потоки по-прежнему выполнять код внутри синхронизированного блока, потому что блокировка не связана с экземпляром this?

Я знаю, что синхронизация метода или блока кода предотвращает одновременный доступ нескольких потоков к этому блоку/методу, но какова цель указания объекта для блокировки и в чем разница в способе указания объекта, как в приведенные выше примеры?


person ziggy    schedule 24.07.2011    source источник
comment
См. также Синхронные методы и блокировка потоков.   -  person Andrew Thompson    schedule 24.07.2011
comment
Также посмотрите здесь: Java Concurrency/Multithreading — Tutorial   -  person Hovercraft Full Of Eels    schedule 24.07.2011
comment
@Andrew: ах, я думал, ты имел в виду статью, но теперь вижу, что это мультипост.   -  person Hovercraft Full Of Eels    schedule 24.07.2011
comment
@HFOE .. это мультипост. Действительно. Меня отругали за то, что я давно упомянул об этом в другом вопросе (в основном за то, что ввел его в качестве ответа, а затем отказался удалить ответ), поэтому теперь примените более «тонкий» подход. ;)   -  person Andrew Thompson    schedule 24.07.2011
comment
По сути, у нас недостаточно информации (достаточно кода), чтобы сказать вам, почему программист решил по-разному в двух случаях. Это может привести к путанице при использовании synchronized(this), потому что он также синхронизируется с методами synchronized, и вы можете получить тупиковые ситуации. Вы также можете столкнуться с взаимоблокировками, если кто-то использует объект в качестве блокировки где-то еще в коде. Я помню, как читал комментарий одного из создателей Java, в котором говорилось, что они не должны были разрешать блокировку объектов, а только использование выделенных блокировок (т.е. java.util.concurrent.locks).   -  person toto2    schedule 24.07.2011
comment
@Andrew: пожалуйста, используйте наведение, а не HFOE, чтобы направить комментарий мне, поскольку @ HFOE не направляет комментарий в мой почтовый ящик. Чтобы узнать больше об этом, ознакомьтесь с: meta: how-do-comment-replies-work   -  person Hovercraft Full Of Eels    schedule 24.07.2011
comment
@hover Спасибо за совет и ссылку - это проясняет для меня кое-что.   -  person Andrew Thompson    schedule 24.07.2011


Ответы (3)


Какова цель указания объекта для блокировки?

Часто проще выполнить синхронизацию на экземпляре this или экземпляре Class (для статических методов). Но бывают случаи, когда вам нужно синхронизировать конкретный объект вместо неявной блокировки (this). К таким случаям относятся:

Ниже приведен пример использования разделенной блокировки:

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, поток должен получить блокировку, связанную с текущим объектом. В обоих случаях поток должен получить блокировку; примеры отличаются только объектом, который используется в качестве замка.

person Vineet Reynolds    schedule 24.07.2011

Синхронизация объекта означает, что другим блокам, которые синхронизируются с тем же объектом, придется ждать. Например:

public void methodA() {
   synchronized(obj) {
      //Do one job
   }
}

public void methodB() {
   synchronized(obj) {
      //Do another job
   }
}

Если вы вызываете methodA() в одном потоке, а затем вызываете methodB() в другом потоке, methodB() не завершится до завершения methodA().

person Petar Minchev    schedule 24.07.2011

Блок synchronized — это монитор, в котором не упоминаются подробности блокировки и разблокировки мьютекса. Поскольку каждый объект в Java имеет внутреннюю блокировку (см. исходный код класса Object), при использовании оператора synchronized JVM поможет вам синхронизировать критическую секцию. Вы также можете самостоятельно синхронизировать блок, используя ReentrantLock в пакете java.util.concurrent.locks.

person Summer_More_More_Tea    schedule 24.07.2011