Похоже, что каждый из ваших методов дважды блокирует мьютекс, но разблокирует его только один раз. Они делают что-то вроде этого:
if(preparedLock.tryLock()) { // locks the mutex if the result is true.
preparedLock.lock(); // This locks it A SECOND TIME.
try{
...
}finally{
preparedLock.unlock(); // This unlocks it ONCE.
}
}
// At this point, the thread still has one lock on preparedLock
Объект ReentrantLock
позволяет одному потоку хранить несколько заявок на мьютекс. Это полезно для таких ситуаций:
private final Lock myMutex = new ReentrantLock();
public void foobar(...) {
myMutex.lock();
try {
...
}
finally {
myMutex.unlock();
}
}
public void bizzwizz(...) {
myMutex.lock();
try {
...
foobar(...);
...
}
finally {
myMutex.unlock();
}
}
И foobar (), и bizzwizz () являются публичными функциями. Мы хотим, чтобы другие классы могли вызывать любой из них, но мы также хотим, чтобы оба они заблокировали myMutex
, и мы хотим, чтобы bizzwizz()
мог вызывать foobar()
.
Если myMutexне реентерабельный, у нас возникнет проблема, когда bizzwizz()
будет вызываться foobar()
, потому что foobar()
попытается заблокировать мьютекс, который уже был заблокирован. Обычно случается так, что вызов lock()
не будет возвращаться, пока блокировка не будет снята потоком, которому она принадлежит. Но этого никогда не произойдет, потому что тот же самый поток, которому он принадлежит, вызывает тот, который вызывает lock()
. Эта ситуация иногда называется self deadlock .
A reentrant mutex позволяет одному потоку иметь несколько утверждений на мьютекс. Каждый вызов lock()
увеличивает количество заявок на единицу, а каждый вызов unlock()
уменьшает его. Потоки B, C и D не смогут lock()
мьютекс, если поток A имеет как минимум одно утверждение.