/* * Copyright 2014 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.utilities.concurrency; import com.google.common.collect.Lists; import java.util.AbstractQueue; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class DynamicPriorityBlockingQueue<T> extends AbstractQueue<T> implements BlockingQueue<T> { private Comparator<T> comparator; private List<T> elements = Lists.newLinkedList(); /** * Lock used for all public operations */ private final ReentrantLock lock; /** * Condition for blocking when empty */ private final Condition notEmpty; public DynamicPriorityBlockingQueue(Comparator<T> comparator) { this.comparator = comparator; lock = new ReentrantLock(); notEmpty = lock.newCondition(); } @Override public boolean add(T t) { return offer(t); } @Override public void put(T t) throws InterruptedException { offer(t); } @Override public boolean offer(T t, long timeout, TimeUnit unit) throws InterruptedException { return offer(t); } @Override public boolean offer(T t) { lock.lock(); try { elements.add(t); notEmpty.signal(); return true; } finally { lock.unlock(); } } @Override public T poll() { lock.lock(); try { return dequeue(); } finally { lock.unlock(); } } @Override public T take() throws InterruptedException { lock.lockInterruptibly(); try { T result = dequeue(); while (result == null) { notEmpty.await(); result = dequeue(); } return result; } finally { lock.unlock(); } } @Override public T poll(long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); lock.lockInterruptibly(); try { T result = dequeue(); while (result == null && nanos > 0) { nanos = notEmpty.awaitNanos(nanos); result = dequeue(); } return result; } finally { lock.unlock(); } } @Override public T peek() { lock.lock(); try { return elements.size() == 0 ? null : elements.get(0); } finally { lock.unlock(); } } private T dequeue() { if (elements.size() == 0) { return null; } T smallest = elements.remove(0); ListIterator<T> iterator = elements.listIterator(); while (iterator.hasNext()) { T next = iterator.next(); if (comparator.compare(smallest, next) > 0) { iterator.set(smallest); smallest = next; } } return smallest; } @Override public int remainingCapacity() { return Integer.MAX_VALUE; } @Override public int drainTo(Collection<? super T> c) { lock.lock(); try { int count = 0; while (!elements.isEmpty()) { c.add(elements.remove(0)); count++; } return count; } finally { lock.unlock(); } } @Override public int drainTo(Collection<? super T> c, int maxElements) { lock.lock(); try { int count = 0; while (!elements.isEmpty() && count < maxElements) { c.add(elements.remove(0)); count++; } return count; } finally { lock.unlock(); } } @Override public int size() { lock.lock(); try { return elements.size(); } finally { lock.unlock(); } } @Override public Iterator<T> iterator() { throw new UnsupportedOperationException(); } }