ReentrantLock: блокировка / разблокировка скорости в однопоточном приложении - PullRequest
1 голос
/ 27 ноября 2011

Я использую некоторые ReentrantLock для синхронизации доступа к списку в нескольких потоках. Я просто пишу общий

try {
   lock.lock();
   ... modify list here
} finally {
   lock.unlock();
}

везде. Я только что заметил, что большинство списков в коде будет использоваться только одним потоком (gui dispatch-).

Теперь я не уверен, должен ли я снять блокировку в этих случаях, так как это может ускорить мой код. Как быстро работает ReentrantLock? Является ли операция lock () более быстрой, если сам поток был «предыдущим владельцем» блокировки, даже если он ее разблокировал ()?

Ответы [ 4 ]

3 голосов
/ 27 ноября 2011

Независимо от того, насколько быстро это будет, оно, безусловно, будет медленнее, чем без блокировки, хотя бы на очень небольшую величину.Я лично предпочел бы правильность, а не увеличение скорости (что не будет много) и сохранить код таким, какой он есть (особенно, если он уже проверен), если только вы не определили «блокировку» как узкое место.

2 голосов
/ 27 ноября 2011

3 вещи:

  • lock.lock () должен находиться за пределами блока try.

  • , если вы работаете на одномблокировка ядра процессора очень дешево.Тогда в зависимости от архитектуры процессора приобретение / выпуск может быть дешевым или не очень большим.Nehalem + в порядке.

  • , если вам не нужны блокировки для чего-либо еще, synchronized может быть лучшим подходом, поскольку JVM может огрубить мониторы и / или сместить блокировку () emв однопоточном приложении.Опять же, производительность смещенных блокировок сильно зависит от архитектуры процессора.

1 голос
/ 27 ноября 2011

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

0 голосов
/ 27 ноября 2011

Я действительно не понимаю, является ли ваше приложение однопоточным или многопоточным. Название говорит об одном, а из тела мы можем вывести другое. Я предполагаю, что вы используете более одного потока (иначе вопрос не имеет смысла - зачем вам использовать синхронизацию между ... менее чем двумя потоками?!).

Там может быть более серьезная проблема, чем производительность. Видимость .

Вы не предоставляете никаких подробностей о той части кода, в которой вы ...modify a list..., однако очень важно знать детали: в зависимости от того, как вы это сделали, если вы удалите блокировку, что может произойти is: один поток изменяет список, а другой поток не видит эти изменения (или видит частичные, скорее всего, несогласованные изменения).

Аспект синхронизации, который, по-видимому, отсутствует, заключается в том, что, если не использовать некоторые конкретные конструкции (блокировки / изменчивые переменные / конечные поля), нет никаких гарантий, что один поток увидит то, что другой поток сделал с памятью.

В этом случае ваша гарантия дается блокировками: когда поток T1 получает блокировку L, гарантируется, что он увидит все изменения, внесенные в память потоком T2, прежде чем T2 снимет блокировку L.

   T2            T1
acquires L
modifies a
modifies b
releases L
modifies c    acquires L
              reads a
              reads b
              reads c
              releases L

В этом случае гарантируется, что T1 увидит правильные значения для a и b, но нет никакой гарантии относительно того, что он увидит при чтении c.

Если вы снимаете блокировки, убедитесь, что ваша структура данных поточно-ориентирована, и, если содержащиеся в ней данные (т. Е. Ваши объекты внутри списка) не поточнобезопасны, убедитесь, что между каждой модификацией и последующим извлечением данных, которые вы вызываете отношение случается до , в противном случае произойдут плохие вещи.

...