All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hybhub.util.concurrent.ConcurrentSetBlockingQueue Maven / Gradle / Ivy

There is a newer version: 2.16.0
Show newest version
package com.hybhub.util.concurrent;

import java.util.Collection;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A blocking queue backed by a set so duplicates inside the queue are not
 * allowed.
 * 
 * @param  the type of elements held in this queue
 */
public class ConcurrentSetBlockingQueue extends ConcurrentSetQueue implements BlockingQueue {

	public ConcurrentSetBlockingQueue(final int capacity) {
		super(capacity);
	}

	public ConcurrentSetBlockingQueue() {
		this(Integer.MAX_VALUE);
	}

	@Override
	public int remainingCapacity() {
		return (capacity - count.get());
	}

	@Override
	public E poll(final long timeout, final TimeUnit unit) throws InterruptedException {
		E x;
		int c;
		long nanos = unit.toNanos(timeout);
		final AtomicInteger count = this.count;
		final ReentrantLock takeLock = this.takeLock;
		takeLock.lockInterruptibly();
		try {
			while (count.get() == 0) {
				if (nanos <= 0) {
					return null;
				}
				nanos = notEmpty.awaitNanos(nanos);
			}
			x = set.iterator().next();
			set.remove(x);
			c = count.getAndDecrement();
			if (c > 1) {
				notEmpty.signal();
			}
		} finally {
			takeLock.unlock();
		}
		if (c == capacity) {
			signalNotFull();
		}
		return x;
	}

	@Override
	public void put(final E e) throws InterruptedException {
		if (e == null) {
			throw new NullPointerException();
		}

		int c;
		final AtomicInteger count = this.count;
		fullyLock();
		try {
			if (set.contains(e)) {
				return;
			}

			while (count.get() == capacity) {
				notFull.await();
			}
			set.add(e);
			c = count.getAndIncrement();
			if (c + 1 < capacity) {
				notFull.signal();
			}
		} finally {
			fullyUnlock();
		}
		if (c == 0) {
			signalNotEmpty();
		}
	}

	/**
	 * 	@see BlockingQueue
	 *  @return {@code true} upon success and {@code false} if no space is currently available
	 */
	@Override
	public boolean offer(final E e, final long timeout, final TimeUnit unit) throws InterruptedException {
		if (e == null) {
			throw new NullPointerException();
		}
		long nanos = unit.toNanos(timeout);
		int c;
		final ReentrantLock putLock = this.putLock;
		final AtomicInteger count = this.count;
		putLock.lockInterruptibly();
		try {
			if (set.contains(e)) {
				// Space is available and entry is already in the queue so return true 
				return true;
			}

			while (count.get() == capacity) {
				if (nanos <= 0) {
					return false;
				}
				nanos = notFull.awaitNanos(nanos);
			}
			set.add(e);
			c = count.getAndIncrement();
			if (c + 1 < capacity) {
				notFull.signal();
			}
		} finally {
			putLock.unlock();
		}
		if (c == 0) {
			signalNotEmpty();
		}
		return true;
	}

	@Override
	public E take() throws InterruptedException {
		E x;
		int c;
		final AtomicInteger count = this.count;
		final ReentrantLock takeLock = this.takeLock;
		takeLock.lockInterruptibly();
		try {
			while (count.get() == 0) {
				notEmpty.await();
			}
			x = set.iterator().next();
			set.remove(x);
			c = count.getAndDecrement();
			if (c > 1) {
				notEmpty.signal();
			}
		} finally {
			takeLock.unlock();
		}
		if (c == capacity) {
			signalNotFull();
		}
		return x;
	}

	@Override
	public int drainTo(final Collection c) {
		return drainTo(c, Integer.MAX_VALUE);
	}

	@Override
	public int drainTo(final Collection c, final int maxElements) {
		if (c == null) {
			throw new NullPointerException();
		}
		if (c == this) {
			throw new IllegalArgumentException();
		}
		if (maxElements <= 0) {
			return 0;
		}
		boolean signalNotFull = false;
		final ReentrantLock takeLock = this.takeLock;
		takeLock.lock();
		try {
			int n = Math.min(maxElements, count.get());
			int i = 0;
			try {
				while (i < n) {
					E e = set.iterator().next();
					set.remove(e);
					c.add(e);
					++i;
				}
				return n;
			} finally {
				if (i > 0) {
					signalNotFull = (count.getAndAdd(-i) == capacity);
				}
			}
		} finally {
			takeLock.unlock();
			if (signalNotFull) {
				signalNotFull();
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy