2015-04-23 26 views
3

我正在使用LinkedBlockingQueue队列来实现producer-consumer pattern的TCP/IP事件传输,我使用boolean offer(e)这意味着一旦队列达到其容量,新的传入事件将被忽略(丢弃)和它返回false如何设置容量为Java DelayQueue

现在我必须将事件持续一个可配置的时间(比如2秒),所以我决定使用DelayQueue,它只能在时间到期时才能保存元素和释放元素。

不幸的是,DelayQueue无界。我想知道是否有一种方法来设置容量DelayQueuedelayQueue.size() == CAPACITY总是可靠?

+0

当队列已满时,是否要等到空间可用并添加到队列中?什么是延迟? –

+0

延迟与队列容量无关,一个元素只能在时间到期时从队列中取出。检查队列的目的是满的是我想要统计被丢弃的事件的数量。 – haifzhan

+0

您可以在添加或子类DelayQueue以使offer()执行此操作之前检查大小()。 –

回答

2

这是一个相当大的问题,因为我们需要访问使用DelayQueue如果我们要继承它或委托给它,并且锁是私人在DelayQueue内部锁。

我们不能用第二个锁定,因为这会导致与take问题。你也许可以自己实现这一点,但是这样做比自己实现DelayQueue还要多,所以这可能不是你想要的。

我们可以使用反射来访问锁。但请注意,这不是最好的想法,因为它依赖于DelayQueue的实现细节。它可能不适用于所有的JRE,甚至可能会因为您更改运行的JRE版本而中断。这就是说,我认为这是解决您的问题最简单的方法,尽管有点肮脏。

/** 
* Bounded implementation of {@link DelayQueue}. This implementation uses 
* reflection to access the internal lock in {@link DelayQueue} so might 
* only work on the Oracle 1.8 JRE. 
* @param <T> 
*/ 
public class BoundedDelayQueue<T extends Delayed> extends DelayQueue<T> { 

    // Lock used to synchronize every operation 
    private final transient ReentrantLock lock; 

    // The limit 
    private final int limit; 

    BoundedDelayQueue(int limit) { 
     try { 
      // Grab the private lock in DelayQueue using reflection so we can use it 
      // to gain exclusive access outside of DelayQueue 
      Field lockField = DelayQueue.class.getDeclaredField("lock"); 
      lockField.setAccessible(true); 
      this.lock = (ReentrantLock) lockField.get(this); 
     } catch (NoSuchFieldException | IllegalAccessException e) { 
      throw new Error("Could not access lock field", e); 
     } 
     this.limit = limit; 
    } 

    @Override 
    // All the various ways of adding items in DelayQueue delegate to 
    // offer, so we only have to override it and not the other methods 
    public boolean offer(final T t) { 
     // Lock the lock 
     lock.lock(); 
     try { 
      // Check the size limit 
      if(size() == limit) { 
       return false; 
      } 
      // Forward to superclass 
      return super.offer(t); 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 

请注意,这不以超时实现offer,如果你需要,你必须自己做。

+0

感谢您的回复。为什么使用反射? BoundedDelayQueue的实例将与多线程共享,我试图初始化BoundedDelayQueue类中的一个锁,并在'offer(boolean)'方法中锁定/解锁,它是线程安全的,这里的锁是静态的还是非静态的会影响线程安全吗?谢谢:) – haifzhan

+1

我们必须使用反射,因为我们需要DelayQueue使用的完全相同的锁,并且访问它的唯一方法是通过反射。如果我们使用一个单独的锁,我们必须覆盖并重新实现所有需要同步的方法 - 并且在那一点上,我们可能只是从头开始重新实现DelayQueue,因为这基本上就是我们要做的。 – Raniz

+0

这里的锁不是静态的,它与DelayQueue使用的完全相同,因此它是线程安全的。 – Raniz