/* * Copyright 2012, CMM, University of Queensland. * * This file is part of Paul. * * Paul is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Paul is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Paul. If not, see <http://www.gnu.org/licenses/>. */ package au.edu.uq.cmm.paul.grabber; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; /** * This is a special-purpose blocking queue class with infinite capacity. * The API adds a pause() method that allows you to suspend * the methods that remove elements from the front of the queue. Calls * to these methods are blocked until some other thread calls resume(). * All other method calls are allowed to proceed. * <p> * BEWARE: the class uses a linked list and simple mutex synchronization. * Don't expect good performance if you use it in a use-case where there * are lots of producer and/or consumer threads. (It is designed for a * use-case where there is one producer and one consumer ...) * * @author scrawley * * @param <E> the queue element type */ public class PausableQueue<E> implements BlockingQueue<E> { private boolean paused; private LinkedList<E> elements = new LinkedList<E>(); @Override public synchronized E remove() { return elements.removeFirst(); } @Override public synchronized E poll() { return elements.poll(); } @Override public synchronized E element() { return elements.element(); } @Override public synchronized E peek() { return elements.peekFirst(); } @Override public synchronized int size() { return elements.size(); } @Override public synchronized boolean isEmpty() { return elements.isEmpty(); } @Override public synchronized Iterator<E> iterator() { return elements.iterator(); } @Override public synchronized Object[] toArray() { return elements.toArray(); } @Override public synchronized <T> T[] toArray(T[] a) { return elements.toArray(a); } @Override public synchronized boolean containsAll(Collection<?> c) { return elements.containsAll(c); } @Override public synchronized boolean addAll(Collection<? extends E> c) { this.notifyAll(); return elements.addAll(c); } @Override public synchronized boolean removeAll(Collection<?> c) { return elements.removeAll(c); } @Override public synchronized boolean retainAll(Collection<?> c) { return elements.retainAll(c); } @Override public synchronized void clear() { elements.clear(); } @Override public synchronized boolean add(E e) { this.notify(); return elements.add(e); } @Override public synchronized boolean offer(E e) { this.notify(); return elements.add(e); } @Override public synchronized void put(E e) throws InterruptedException { this.notify(); elements.add(e); } @Override public synchronized boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { this.notify(); elements.add(e); return true; } @Override public synchronized E take() throws InterruptedException { while (paused || elements.isEmpty()) { this.wait(); } return elements.remove(); } @Override public synchronized E poll(long timeout, TimeUnit unit) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("negative timeout"); } long now = System.currentTimeMillis(); long deadline = unit.toMillis(timeout) + now; if (deadline < now) { deadline = Long.MAX_VALUE; } while (paused || elements.isEmpty() && (now = System.currentTimeMillis()) < deadline) { this.wait(deadline - now); } return elements.poll(); } @Override public synchronized int remainingCapacity() { return Integer.MAX_VALUE; } @Override public synchronized boolean remove(Object o) { return elements.remove(o); } @Override public synchronized boolean contains(Object o) { return elements.contains(o); } @Override public synchronized int drainTo(Collection<? super E> c) { int size = elements.size(); c.addAll(elements); elements.clear(); return size; } @Override public synchronized int drainTo(Collection<? super E> c, int maxElements) { int count = 0; while (count < maxElements && !elements.isEmpty()) { c.add(elements.removeFirst()); count++; } return count; } public synchronized void pause() { if (!paused) { paused = true; } } public synchronized void resume() { if (paused) { paused = false; this.notifyAll(); } } }