2013-09-03 4 views
3

Я знаю, что если использовать ReentrantLock, он позволяет одному и тому же потоку приобретать один и тот же замок более одного раза. Внутри он имеет счетчик для подсчета количества блокировки. Если вы дважды приобрели один и тот же замок, вам нужно будет выпустить его дважды. Но мой вопрос заключается в том, почему кто-то хочет приобрести блокировку несколько раз, должно ли одно время получить достаточно? Может ли кто-нибудь дать мне общий прецедент?java.concurrent.ReentrantLock - почему мы хотим получить один и тот же замок несколько раз

+0

Такие вещи случаются очень часто с доступом к файлам со считыванием/записью – Cruncher

+0

'http://en.wikipedia.org/wiki/Semaphore_ (программирование)' Здесь есть несколько хороших аналогов. – Cruncher

ответ

6

Рассмотрим следующий случай, когда вам нужен набор операций, который не является атомарным, быть атомарным. Например, вы можете установить значение массива, но при его настройке вернуть его текущее значение. (попробуйте, наконец, удалить для краткости).

final ReentrantLock lock = new ReentrantLock(); 

final Object[] objects = new Object[10] 
public Object setAndReturnPrevious(int index, Object val){ 
    lock.lock(); 
     Object prev = get(index); 
     set(index,val); 
     return prev; 
    lock.unlock(); 
} 
public void set(int index, Object val){ 
    lock.lock(); 
     objects[index] = val; 
    lock.unlock(); 
} 
public Object get(index index){...} 

Если ReentrantLock не может использоваться повторно вы тупиковых на get(index)

+0

Это имеет смысл сейчас, это дифференцировать ReentrantLock для синхронизации (это), правильно? в этом случае sychronized (this) будет deadlock при get (index). – Shengjie

+0

@Shengjie На самом деле 'synchronized' также является реентерабельным, поэтому ни в одном случае вы бы не заблокировали замок. –

3

Предположим, что в классе у вас есть два метода m1 и m2, и синхронизированы, и m2 вызывает m1. В этом случае, если нить a заняла блокировку на m1 и снова заблокировала блокировку, то этот трезад будет продолжать ждать вызова m2 (поскольку он уже имеет блокировку)

2

Рассмотрим синхронизированный пример. То же самое относится к блокировке, но с большим количеством кода.

synchronized int getSum() { 
    return getValue() + getOtherValue(); 
} 

synchronized int getValue() { 
    return value; 
} 

synchronized int getOtherValue() { 
    return value; 
} 

Единственный способ избежать повторного входа - создать заблокированные и разблокированные версии каждого метода. Однако что, если у вас есть два экземпляра A и B. Вызов B, который вызывает A. Как B не знает, чтобы вызвать синхронизированный метод в A.

1

Некоторые утверждают, что следует избегать блокировки реентера. В критическом разделе вы должны точно знать, что происходит. Если локальный критический раздел может вызвать внешний код, который может вызвать локальный код, это кажется довольно сложным и потенциально опасным. Лучше всего иметь только несколько четко определенных критических разделов, содержащих только локальный код.