2015-10-26 7 views
9

ReadWriteLock понижение допускается ReentrantReadWriteLock реализации (tryLock() из приведенного ниже примера всегда возвращает true):Почему обновление ReadWriteLock не разрешено?

void downgrade(final ReadWriteLock readWriteLock) { 
    boolean downgraded = false; 
    readWriteLock.writeLock().lock(); 
    try { 
     // Always true, as we already hold a W lock. 
     final boolean readLockAcquired = readWriteLock.readLock().tryLock(); 
     if (readLockAcquired) { 
      // Now holding both a R and a W lock. 
      assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 1; 
      assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 1; 

      readWriteLock.writeLock().unlock(); 
      downgraded = true; 
      try { 
       // Now do some work with only a R lock held 
      } finally { 
       readWriteLock.readLock().unlock(); 

       assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 0; 
       assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 0; 
      } 
     } 
    } finally { 
     if (!downgraded) { 
      // Never (we were holding a W lock while trying a R lock). 
      readWriteLock.writeLock().unlock(); 
     } 
     assert ((ReentrantReadWriteLock) readWriteLock).getReadHoldCount() == 0; 
     assert ((ReentrantReadWriteLock) readWriteLock).getWriteHoldCount() == 0; 
    } 
} 

Какова была идея не позволяет апгрейд замка подобным образом? Метод tryLock() для Write Блокировки ниже может безопасно вернуть true ш риска/оа для взаимоблокировки при отсутствии других потоков, проведение чтения замка:

void upgrade(final ReadWriteLock readWriteLock) { 
    readWriteLock.readLock().lock(); 
    try { 
     // Always false: lock upgrade is not allowed 
     final boolean writeLockAcquired = readWriteLock.writeLock().tryLock(); 
     // ... 
    } finally { 
     readWriteLock.readLock().unlock(); 
    } 
} 
+4

Если вы используете Java 8, вы можете захотеть взглянуть на 'StampedLock'. В более общем плане, вы можете захотеть посмотреть [это видео] (https://www.youtube.com/watch?v=Q_0_1mKTlnY) у Анжелики Лангер. Кольца колокола, верно? ;) – fge

ответ

2

Первого, отметим, что обновление и понижение рейтинга являются не эквивалентны по семантической сложности для ReadWriteLock с.

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

Чтобы использовать его, механизм обновления должен предотвращать взаимоблокировки в случае, если два потока чтения одновременно пытаются обновить (или, в частности, для ReentrantReadWriteLock, если один поток чтения, содержащий несколько блокировок чтения, пытается обновить). Кроме того, механизм должен указать, как будет обрабатываться неудачный запрос на обновление (будет ли он заблокирован для чтения), и это еще менее тривиально.

Как вы, вероятно, видите сейчас, полностью справиться с этими проблемами в ReentrantReadWriteLock неудобно сказать меньше (все же, это то, что NET ReaderWriterLock пытается, и я думаю, на самом деле это действительно удается). Я предполагаю, что в то время как final boolean writeLockAcquired = readWriteLock.writeLock().tryLock(); мог быть преуспел в некоторых тривиальных случаях, возможность обновления по-прежнему не была бы достаточно хороша для общего использования - при достаточно сильных конфликтах, если вы потеряете гонку за блокировку записи, вы находитесь в как если бы вы разблокировали блокировку чтения и попытались получить блокировку записи (оставляя возможность кому-то еще прокрасться и взять блокировку записи между ними).

Хороший способ обеспечения возможности блокировки - это разрешить только один поток для обновления - это то, что делает ReentrantReadWriteUpdateLock или что делает .NET ReaderWriterLockSlim. Тем не менее, я бы рекомендовал Java 8-х StampedLock как:

  • при низкой конкуренции его оптимистичные читает гораздо быстрее, чем при использовании блокировки чтения
  • его API гораздо менее ограничительный об обновлении (от оптимистического чтения читать замок писать замок)
  • мои различные попытки создать реалистичный JMH ориентир, где один из других подобных замков бьет он почти всегда не удалось
Смежные вопросы