Может ли такой код привести к deadlock?
#java #concurrency
class A {
public synchronized void foo() {
...
}
}
class B extends A {
public synchronized void foo() {
...
super.foo();
}
}
Как мы видим, оба метода foo в классе A и классе B synchronized. Синхронизация в данном случае на одном и том же объекте.
Обычно deadlock возникает в многопоточной среде, когда потоки получают локи на хотя бы двух объектах в разном порядке.
Например,
void foo(Object obj1, Object obj2) {
synchronized(obj1) {
synchronized(obj2) {
....
}
}
}
и один поток вызывает foo(obj1, obj2), а второй поток вызывает foo(obj2, obj1), то может возникнуть deadlock. Т.к. один поток получит лок на один объект и будет ждать получения лока на второй объект. А второй поток наоборот. Получит сначала лок на второй и будет ждать получения лока на первый объект, который держит первый поток.
В данном случае ситуация иная. У нас всего один объект.
Давайте посмотрим, что будет если у нас всего один поток.
Например, у нас такой код B b = new B(); b.foo();
Вызывающий поток получит лок на B при вызове foo из класса B. Далее дойдет до кода super.foo(). Этот вызов тоже synchronized на том же объекте.
Лок на этот объект уже получен вызывающим потоком. И если бы в Java synchronized был бы не reentrant, то поток бы ждал пока лок отпустят, чтобы его получить. В таком случае мог бы возникнуть deadlock. Но в силу того, что в Java synchronized в Java Reentrant один и тот же поток может получить лок на один и тот же объект множество раз. Для каждого такого лока (монитора) есть некий счетчик(сколько раз получен монитор на данный объект) и идентификатор потока, который его получил. Лок может получить только один поток, но множество раз. Как только счетчик упадет до нуля, это значит, что другой поток может получить теперь монитор (лок) на данном объекте.
Поэтому deadlock не возникнет благодаря свойству reentrancy локов при помощи synchronized (intrinsic locks).
Post #177
1.5K
- 👍 14