2013-06-24 3 views
1

Я видел вопрос How do determine if an object is locked (synchronized) so not to block in Java?
Но у меня есть проблема, по которой я не могу найти решение.
В моем веб-приложении есть процесс, в котором обновляется контейнер данных, и это может занять много времени. Обновление необходимо сделать с интервалом времени. Конечно, когда одно обновление все еще работает на контейнере, другое не может (чтобы не повреждать данные в контейнере).
Я хочу использовать фоновый поток для обновления контейнера. Несколько фоновых работников могут работать одновременно на нескольких контейнерах (разные рабочие для разных пользовательских сеансов, каждый пользовательский сеанс может иметь разные данные в своем контейнере).
Конечно, я могу сделать synchronize(myContainer) в рабочем состоянии, чтобы любой другой рабочий не обновлял данный конкретный контейнер. Но я скорее хочу проверить, работает ли какой-либо рабочий над контейнером и выйдет, если есть. Также я бы не хотел менять код контейнера, поэтому я бы не хотел добавлять ReentrantLock внутри класса контейнера и блокировать его.
Итак, у рабочего есть MyContainer экземпляр и вы хотите определить, обновляет ли какой-либо другой рабочий объект этот экземпляр контейнера.Как синхронизировать объект без блокировки?

Любые идеи, как достичь этого?

ответ

2

использовать AtomicBoolean, поместите этот код в MyContainer классе:

AtomicBoolean isRefreshing = new AtomicBoolean(false); 

void refresh() { 
    if (isRefreshing.compareAndSet(false, true)) { 
    try { 
     // refresh 
    } finally { 
     isRefreshing.set(false); 
    } 
    } 
} 

Если вы не можете коснуться MyContainer, может создать RefreshWrapper удерживающий AtomicBoolean и экземпляр MyContainer.

1

Я бы поставил контейнеры в ConcurrentLinkedQueue и имею рабочие потоки poll очередь т.е.

Container container; 
while((container = queue.poll()) != null) { 
    container.refresh(); 
} 

Тогда у вас есть два варианта, в зависимости от того, контейнеров отслеживания, когда они обновляются.

  • Если они есть, то вы можете вернуть offer обновленные контейнеры в очередь, как только они будут обновлены. Вы можете использовать предохранение if(container.refreshTime < X), чтобы убедиться, что вы не обновляете контейнер дважды за тот же промежуток времени.
  • Если они не то вы можете либо
    • Используйте два ConcurrentLinkedQueues и чередуются между ними: poll на queue1 и offer обновилась контейнера на queue2, и когда queue1 пуст сон до следующего временного интервала, в котором точка poll на queue2 и offer обновленные контейнеры на queue1.
    • Или сохраните массив контейнеров в основном потоке, и offer контейнеры возвращаются в очередь, когда рабочие потоки завершили обновление всех контейнеров и отправились спать.
+1

'ConcurrentLinkedQueue' является неблокирующим, что означает, что OP не является осторожным, цикл while может сделать серьезную занятость-поворот –

+0

@John Vint Я предполагаю, что в очереди уже хранятся все контейнеры в то время, когда рабочие потоки запускаются, как в случае, если контейнеры немедленно добавляются в очередь или немедленно добавляются в другую очередь, которая затем чередуется с исходной очередью. Если это не так, лучше выбрать «BlockingQueue» - цикл в моем ответе не будет занят, если контейнеры будут одновременно добавлены и удалены из очереди, но это может привести к преждевременному прекращению использования. –

+0

@JohnVint: На самом деле, мой ответ имеет тот же недостаток, но я думаю, что ограничение частоты обновления выходит за рамки этого вопроса, и у OP должно быть что-то, что можно было бы решить. В противном случае «ScheduledExecutorService» будет хорошим решением. –

0

Если вам необходимо предварительно проверить, если объект не был уже заблокирован другим потоком, это должно быть возможно с Thread.holdsLock методом.

Если этого недостаточно, просмотрите advanced lock classes. Эти блокировки предоставляют богатый набор функций (убедитесь, что они ждут блокировки, пытаются заблокировать тайм-аут, заблокировать прерывание и т. Д.). Они должны предоставить достаточно возможностей для решения вашей проблемы.