2017-01-22 2 views
3

В API docs из Lock интерфейса для метода tryLock(), этот пример кода наклеивается,Пример использования для Lock.tryLock()

Типичное использование идиомы для этого метода было бы:

Lock lock = ...; 
    if (lock.tryLock()) { 
     try { 
      // manipulate protected state 
     } finally { 
      lock.unlock(); 
     } 
    } else { 
     // perform alternative actions 
    } 

Мой вопрос в том, что этот прецедент не существовал до того, как Java 5 или люди использовали его с помощью некоторых других методов?

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

Может ли кто-нибудь объяснить реальные случаи использования?

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

+0

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

ответ

1

Один прямой вариант использования - это поток, обрабатывающий партию элементов, изредка пытающийся зафиксировать обработанные элементы. Если получение блокировки не удастся, элементы будут зафиксированы в следующей успешной попытке или в финальной обязательной фиксации.

Другой пример можно найти в самой JRE, ForkJoinTask.helpExpungeStaleExceptions() - это метод выполнения задачи, который может выполняться произвольным потоком, но только по одному, поэтому только один поток, успешно получивший блокировку, выполнит его , все остальные вернутся, так как недоступность блокировки подразумевает, что уже существует поток, выполняющий задачу.


можно реализовать подобную функцию до Java 5, если вы разделите внутреннюю фиксирующую функцию, которая не поддерживает быть необязательным, от блокирующей логики, которая может быть представлена ​​в виде обычного состояния объекта. Пример This answer.

+0

Можете ли вы предоставить прямой пример? Описание для меня не очевидно – gstackoverflow

+0

@gstackoverflow: Я уже связан с примером. – Holger

+0

Я не являюсь экспертом в составе ForkJoinPool, поэтому достаточно сложно понять, почему в этом случае использовался tryLock. – gstackoverflow

2

Причина написания кода в этом примере - если у вас есть поток, который выполняет несколько заданий.

Представьте, что вы поместите его в петлю:

while (true) { 
    if (taskA_needsAttention() && taskA_lock.tryLock()) { 
     try { 
      ...do some work on task A... 
     } finally { 
      taskA_lock.unlock(); 
     } 
    } else if (taskB_needsAttention() && taskB_lock.tryLock()) { 
     try { 
      ...do some work on task B... 
     } finally { 
      taskB_lock.unlock(); 
     } 
    } else ... 
} 

Лично я предпочел бы не писать такой код. Я бы предпочел, чтобы разные задачи отвечали за задачу A и задачу B или еще лучше, чтобы использовать объекты, представленные в пул потоков .

+0

Спасибо, это имеет смысл! –

1

Мой вопрос в том, что этот прецедент не существовал до того, как Java 5 или люди использовали его с помощью некоторых других методов?

Интерфейс Lock был добавлен в Java 5, это то, что вы имеете в виду? Не знаю, что было раньше.

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

Несомненно. На самом деле сейчас написал один из них.Моя конкретная реализация Lock - это распределенная блокировка, которая распределяется между кластерами серверов. Метод lock.tryLock(...) вызывает вызовы RPC кластеру и ожидает ответов. Очень возможно, что несколько узлов, возможно, пытаются заблокировать, и их действия могут столкнуться, заставляя задерживать и, конечно же, один замок сбой. Это либо может вернуть false, либо таймаут, и в этом случае мой код просто ждет и повторит попытку. Мой код буквально:

if (!clusterLock.tryLock(TRY_LOCK_TIME_MILLIS, TimeUnit.MILLISECONDS)) { 
    logger.warn("Could not lock cluster lock {}", beanName); 
    return; 
} 

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

Вот еще одно место в моем коде, где я использую tryLock(...)

// need to wait for the lock but log 
boolean locked = false; 
for (int i = 0; i < TRY_LOCK_MAX_TIMES; i++) { 
    if (lock2.tryLock(100, TimeUnit.MILLISECONDS)) { 
     logger.debug("Lock worked"); 
     locked = true; 
     break; 
    } else { 
     logger.debug("Lock didn't work"); 
    } 
}