Я пытаюсь понять, что делает блокировку параллелизма настолько важной, если ее можно использовать synchronized (this)
. В коде ниже, я могу сделать либо:
- синхронизировать весь метод или синхронизировать уязвимую область (
synchronized(this){...}
) - ИЛИ заблокируйте уязвимую область кода с помощью ReentrantLock.
Код:
private final ReentrantLock lock = new ReentrantLock();
private static List<Integer> ints;
public Integer getResult(String name) {
.
.
.
lock.lock();
try {
if (ints.size()==3) {
ints=null;
return -9;
}
for (int x=0; x<ints.size(); x++) {
System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
}
} finally {
lock.unlock();
}
return random;
}
synchronized(this){synchronized(this){//some code}}
не вызовет блокировку. Для внутренней блокировки, если они получают монитор на ресурсе и если они хотят его снова, они могут получить его без мертвой блокировки.Ответы:
ReentrantLock является неструктурированным , в отличии от
synchronized
конструкций - т.е. вам не нужно использовать блочную структуру для запирания и даже можете держать блокировку через методу. Пример:Такой поток невозможно представить с помощью одного монитора в
synchronized
конструкции.Кроме того,
ReentrantLock
поддерживает блокировку опроса и прерываемые ожидания блокировок , которые поддерживают тайм-аут .ReentrantLock
также имеется поддержка настраиваемой политики справедливости , что позволяет более гибко планировать потоки.ReentrantLock
также может быть более масштабируемым , выступая намного лучше при более высокой конкуренции. Вы можете прочитать больше об этом здесь .Это требование было оспорено, однако; см. следующий комментарий:
Когда вы должны использовать
ReentrantLock
с? Согласно этой статье developerWorks ...источник
ReentrantLockPseudoRandom
код в ссылке Lycog использует совершенно новые неконтролируемые блокировки при каждом вызовеsetSeed
иnext
ReentrantReadWriteLock
это специализированная блокировка, тогда как блокировкаsynchronized(this)
общего назначения. Они похожи, но не совсем одинаковы.Вы правы в том, что вы можете использовать
synchronized(this)
вместо,ReentrantReadWriteLock
но обратное не всегда верно.Если вы хотите лучше понять, что заставляет
ReentrantReadWriteLock
особого искать информацию о синхронизации потоков производитель-потребитель.В целом, вы можете помнить, что синхронизация всего метода и синхронизация общего назначения (с использованием
synchronized
ключевого слова) могут использоваться в большинстве приложений, не слишком задумываясь о семантике синхронизации, но если вам нужно снизить производительность из своего кода, вам может потребоваться изучить другие более тонкие или специальные механизмы синхронизации.Между прочим, использование
synchronized(this)
- и вообще блокировка с использованием экземпляра открытого класса - может быть проблематичным, потому что это открывает ваш код для потенциальных мертвых блокировок, потому что кто-то другой, неосознанно, может попытаться заблокировать ваш объект где-то еще в программе.источник
public class MyLock { private final Object protectedLongLockingMonitor = new Object(); private long protectedLong = 0L; public void incrementProtectedLong() { synchronized(protectedLongLockingMonitor) { protectedLong++; } } }
Со страницы документации оракула о ReentrantLock :
ReentrantLock принадлежит нить последний успешно блокировки, но не открывая его. Поток, вызывающий блокировку, вернется, успешно получив блокировку, когда блокировка не принадлежит другому потоку. Метод вернется немедленно, если текущий поток уже владеет блокировкой.
Конструктор для этого класса принимает необязательный параметр справедливости . Если задано значение true, в условиях конкуренции блокировки блокируют доступ к самому длинному ожидающему потоку . В противном случае эта блокировка не гарантирует какой-либо конкретный порядок доступа.
Ключевые функции ReentrantLock согласно этой статье
Вы можете использовать ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock для дальнейшего получения контроля над гранулярной блокировкой при операциях чтения и записи.
Взгляните на эту статью Benjamen об использовании различных типов ReentrantLocks
источник
Вы можете использовать повторяющиеся блокировки с политикой справедливости или тайм-аутом, чтобы избежать истощения потоков. Вы можете применить политику справедливости потоков. это поможет избежать потока, ожидающего навсегда, чтобы добраться до ваших ресурсов.
«Политика справедливости» выбирает следующий выполняемый поток для выполнения. Это основано на приоритете, времени с последнего запуска, бла-бла
Кроме того, Synchronize может блокировать бесконечно, если не может выйти из блока. Reentrantlock может быть установлен тайм-аут.
источник
Синхронизированные блокировки не предлагают никакого механизма ожидания очереди, в котором после выполнения одного потока любой поток, работающий параллельно, может получить блокировку. Из-за этого поток, который находится в системе и работает в течение более длительного периода времени, никогда не получает шанс получить доступ к общему ресурсу, что приводит к голоданию.
Повторно входящие блокировки очень гибки и имеют политику справедливости, в которой, если поток ожидает более длительное время и после завершения текущего выполняющегося потока, мы можем убедиться, что более длинный ожидающий поток получит шанс доступа к общему ресурсу, тем самым уменьшая пропускная способность системы и делает ее более трудоемкой.
источник
Предположим, этот код выполняется в потоке:
Поскольку поток владеет блокировкой, он разрешит множественные вызовы lock (), поэтому он повторно вводит блокировку. Это может быть достигнуто с помощью счетчика ссылок, поэтому он не должен снова получать блокировку.
источник
Следует помнить одну вещь:
имя ' ReentrantLock ' выдает неверное сообщение о другом механизме блокировки, что они не являются повторными. Это неправда. Блокировка, полученная с помощью «synchronized», также возвращается в Java.
Ключевым отличием является то, что «synchronized» использует внутреннюю блокировку (ту, которая есть у каждого объекта), а блокировка API - нет.
источник
Я думаю, что методы wait / notify / notifyAll не принадлежат классу Object, поскольку он загрязняет все объекты методами, которые используются редко. Они имеют больше смысла в специальном классе Lock. Таким образом, с этой точки зрения, возможно, лучше использовать инструмент, который явно предназначен для работы под рукой - то есть ReentrantLock.
источник