2013-06-24 78 views
1

我看过问题How do determine if an object is locked (synchronized) so not to block in Java?
但我有问题,我找不出解决方案。
在我的Web应用程序中,刷新数据容器的过程可能需要很长时间。刷新被迫按时间间隔进行。当然,当一个刷新仍然在容器上工作时,另一个不能(不会破坏容器中的数据)。
我想用后台线程刷新容器。多个后台工作人员可以同时在多个容器上工作(不同用户会话的不同工作人员,每个用户会话的容器中可以有不同的数据)。
当然,我可以在工作人员处做synchronize(myContainer)以强制任何其他工作人员当前未更新此特定容器。但我宁愿要检查是否有任何工人在集装箱上工作并退出,如果是。另外我想不更改容器的代码,所以我不想在容器类中添加ReentrantLock并锁定它。
因此,工作人员有MyContainer实例,并且想要确定是否有其他worker正在刷新此容器实例。如何在不锁定的情况下同步对象?

任何想法如何实现?

回答

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和它们之间的交替:在queue1offerqueue2刷新容器,pollqueue1是空的休眠状态,直到下一个时间间隔,在这一点pollqueue2offer更新容器上queue1
    • 或者,在工作线程完成刷新所有容器并已进入睡眠状态时,将容器的数组保存在主线程中,并将容器保留回队列中。
+1

'ConcurrentLinkedQueue'是非阻塞的,这意味着如果OP不小心,while循环可以做一些严重的忙碌转动 –

+0

@John Vint我假设队列已经拥有所有的容器,工作线程将启动,如果容器立即重新添加到队列中或者立即添加到与原始队列交替的另一个队列中,情况就会如此。如果不是这种情况,那么'BlockingQueue'会是更好的选择 - 如果容器被同时添加到队列中并从队列中移除,我的回答中的循环不会忙碌,但它会冒着过早终止的风险。 –

+0

@JohnVint:实际上,我的答案也有同样的缺点,但我认为限制刷新的频率超出了这个问题的范围,OP应该有适当的方法来解决这个问题。否则,一个'ScheduledExecutorService'将是很好的解决方案。 –

0

如果您需要预先检查对象尚未被其他线程锁定,这应该是可能的Thread.holdsLock方法。如果这还不够,请查看advanced lock classes。这些锁提供了丰富的功能(检查是否在锁上等待,尝试锁定超时,中断锁定等)。他们应该提供足够的功能来解决您的问题。

相关问题