How to set capacity for Java DelayQueue

I used a queue LinkedBlockingQueue

to implement producer-consumer pattern

for sending TCP / IP events, I used boolean offer(e)

which means when the queue reaches its capacity, new incoming events will be ignored (omitted) and this returns false

.

Now I need to hold events for a configurable amount of time (say 2 seconds), so I decided to use DelayQueue

one that can hold items and only release items when the time has elapsed.

Unfortunately, DelayQueue

unlimited . I am wondering if there is a way to set the capacity to DelayQueue

or delayQueue.size() == CAPACITY

always reliable?

+3


source to share


1 answer


This is a serious problem as we need access to the internal locking used by the DelayQueue if we have to subclass or delegate to it, and the locking is private in the DelayQueue.

We cannot use the second lock because it can cause problems with take

. You could implement this yourself, but by doing this you are more than halfway through your own DelayQueue implementation, so this is probably not what you want.

We can access the lock using reflection. Note, however, that this is not the best idea as it relies on the implementation details of DelayQueue. It may not work on all JREs and may even break if you change the version of the JRE you are running on. However, I find this to be the absolute simplest solution to your problem, albeit a little messy.



/**
 * 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();
        }
    }
}

      

Note that this does not implement offer

with a timeout if you need to do it yourself.

+2


source







All Articles