Блокировка блокировки всего объекта? - PullRequest
0 голосов
/ 05 сентября 2018
class Resource{
  public Lock lock = new ReentrantLock();

  public void A(){
    lock.lock();
    try{ .. }
    finally{
      lock.unlock();
    }
  }

  public void B(){
    lock.lock();
    try{ .. }
    finally{
      lock.unlock();
    }

  }


  public void C(){
    ... //Nothing to do with lock here
  }
}

Теперь предположим, что у меня есть 3 потока T1, T2, T3 и один экземпляр Resource с именем resource.

Первое, что запускается, это T1 calls resource.A(). Теперь, скажем, resource.A() занимает 1500 минут, если T2 звонит resource.B() в течение 100-й минуты (что означает, что звонок с T1 выполняется), что произойдет?

Когда я перфорировал lock.lock(), он заблокировал объект или заблокировал метод ?

Спасибо

Ответы [ 3 ]

0 голосов
/ 05 сентября 2018

Первое, что запускается, это вызовы T1 resource.a(). Теперь, скажем, resource.a() занимает 1500 минут, если T2 звонит resource.b() в течение 100-й минуты (что означает, что звонок от T1 выполняется), что происходит?

Что происходит, так это то, что T2 блокируется, пока вызов T1 на resource.b() не снимет блокировку. В этом случае он будет заблокирован на 1400 минут.

Когда я выполнил lock.lock(), он заблокировал объект или заблокировал метод?

Не совсем.

Вы не заблокировали Resource экземпляр:

  1. Экземпляр Resource имеет встроенную блокировку , которая здесь не используется.
  2. Другие темы, вызывающие resource.c(), не будут заблокированы.

Вы на самом деле не блокировали методы. Блокировка внутри методов. Так, например, метод a или метод b могут делать вещи до вызова lock.lock() или после его освобождения.

Что вы на самом деле сделали, так это то, что приобрели блокировку объекта ReentrantLock. В этом случае два из трех методов используют , которые блокируют объект, таким образом, вы в действительности блокируете соответствующих частей этих методов для вызовов различными потоки.

Однако, если вызовы были сделаны одним и тем же потоком (например, если a() вызывается b()), то второй вызов не будет заблокирован. (Вот что означает «реентерабельный» в этом контексте.)

0 голосов
/ 05 сентября 2018

заблокировал ли он объект или заблокировал метод?

Ни. Он заблокировал собственный монитор объекта .

Распространенная ошибка новичка заключается в том, что если поток А синхронизируется с каким-либо объектом o, то другие потоки не смогут использовать или изменять объект o. Это совсем не так. Единственное, что предотвращает поток А путем ввода блока synchronized(o), - это предотвращает одновременную синхронизацию других потоков на одном и том же объекте.

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


Некоторые программисты предпочитают использовать отдельный закрытый объект блокировки:

private static final Object lock = new Object();

public void mymethod(...) {
    synchronized(lock) {
        ...access to this is protected by lock...
    }
}

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

0 голосов
/ 05 сентября 2018

Блокировка получается потоком . Таким образом, если один поток X удерживает блокировку, другие потоки не могут получить блокировку, пока она не будет освобождена X.

В вашем случае метод B не может получить блокировку до того, как метод A снимет блокировку.

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