Back to project page AndroidImageCache.
The source code is released under:
Przemys?aw Jakubczyk Polidea Sp. z o.o. Copyright (c) 2012 All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the follo...
If you think the Android project AndroidImageCache listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. *//from ww w. j av a2 s. c om * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ /* * This file is available under and governed by the GNU General Public * License version 2 only, as published by the Free Software Foundation. * However, the following notice accompanied the original version of this * file: * * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package pl.polidea.thridparty; import java.util.AbstractQueue; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; /** * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on * linked nodes. * <p/> * <p/> * The optional capacity bound constructor argument serves as a way to prevent * excessive expansion. The capacity, if unspecified, is equal to * {@link Integer#MAX_VALUE}. Linked nodes are dynamically created upon each * insertion unless this would bring the deque above capacity. * <p/> * <p/> * Most operations run in constant time (ignoring time spent blocking). * Exceptions include {@link #remove(Object) remove}, * {@link #removeFirstOccurrence removeFirstOccurrence}, * {@link #removeLastOccurrence removeLastOccurrence}, {@link #contains * contains}, {@link #iterator iterator.remove()}, and the bulk operations, all * of which run in linear time. * <p/> * <p/> * This class and its iterator implement all of the <em>optional</em> methods of * the {@link Collection} and {@link Iterator} interfaces. * <p/> * <p/> * This class is a member of the <a href="{@docRoot} * /../technotes/guides/collections/index.html"> Java Collections Framework</a>. * * @param <E> the type of elements held in this collection * @author Doug Lea <doug.lea@somemail.com> * @since 1.6 */ @SuppressWarnings("all") public class LinkedBlockingDeque<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable { /* * Implemented as a simple doubly-linked list protected by a single lock and * using conditions to manage blocking. */ /* * We have "diamond" multiple interface/abstract class inheritance here, and * that introduces ambiguities. Often we want the BlockingDeque javadoc * combined with the AbstractQueue implementation, so a lot of method specs * are duplicated here. */ private static final long serialVersionUID = -387911632671998426L; /** * Maximum number of items in the deque. */ private final int capacity; /** * Main lock guarding all access. */ private final ReentrantLock lock = new ReentrantLock(); /** * Condition for waiting takes. */ private final Condition notEmpty = lock.newCondition(); /** * Condition for waiting puts. */ private final Condition notFull = lock.newCondition(); /** * Pointer to first node. */ private transient Node<E> first; /** * Pointer to last node. */ private transient Node<E> last; /** * Number of items in the deque. */ private transient int count; /** * Creates a <tt>LinkedBlockingDeque</tt> with a capacity of * {@link Integer#MAX_VALUE}. */ public LinkedBlockingDeque() { this(Integer.MAX_VALUE); } /** * Creates a <tt>LinkedBlockingDeque</tt> with the given (fixed) capacity. * * @param capacity the capacity of this deque * @throws IllegalArgumentException if <tt>capacity</tt> is less than 1 */ public LinkedBlockingDeque(final int capacity) { if (capacity <= 0) { throw new IllegalArgumentException(); } this.capacity = capacity; } /** * Creates a <tt>LinkedBlockingDeque</tt> with a capacity of * {@link Integer#MAX_VALUE}, initially containing the elements of the given * collection, added in traversal order of the collection's iterator. * * @param c the collection of elements to initially contain * @throws NullPointerException if the specified collection or any of its elements are null */ public LinkedBlockingDeque(final Collection<? extends E> c) { this(Integer.MAX_VALUE); for (final E e : c) { add(e); } } /** * Links e as first element, or returns false if full. */ private boolean linkFirst(final E e) { if (count >= capacity) { return false; } ++count; final Node<E> f = first; final Node<E> x = new Node<E>(e, null, f); first = x; if (last == null) { last = x; } else { f.prev = x; } notEmpty.signal(); return true; } // Basic linking and unlinking operations, called only while holding lock /** * Links e as last element, or returns false if full. */ private boolean linkLast(final E e) { if (count >= capacity) { return false; } ++count; final Node<E> l = last; final Node<E> x = new Node<E>(e, l, null); last = x; if (first == null) { first = x; } else { l.next = x; } notEmpty.signal(); return true; } /** * Removes and returns first element, or null if empty. */ private E unlinkFirst() { final Node<E> f = first; if (f == null) { return null; } final Node<E> n = f.next; first = n; if (n == null) { last = null; } else { n.prev = null; } --count; notFull.signal(); return f.item; } /** * Removes and returns last element, or null if empty. */ private E unlinkLast() { final Node<E> l = last; if (l == null) { return null; } final Node<E> p = l.prev; last = p; if (p == null) { first = null; } else { p.next = null; } --count; notFull.signal(); return l.item; } /** * Unlink e. */ private void unlink(final Node<E> x) { final Node<E> p = x.prev; final Node<E> n = x.next; if (p == null) { if (n == null) { first = last = null; } else { n.prev = null; first = n; } } else if (n == null) { p.next = null; last = p; } else { p.next = n; n.prev = p; } --count; notFull.signalAll(); } /** * @throws IllegalStateException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public void addFirst(final E e) { if (!offerFirst(e)) { throw new IllegalStateException("Deque full"); } } // BlockingDeque methods /** * @throws IllegalStateException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public void addLast(final E e) { if (!offerLast(e)) { throw new IllegalStateException("Deque full"); } } /** * @throws NullPointerException {@inheritDoc} */ public boolean offerFirst(final E e) { if (e == null) { throw new NullPointerException(); } lock.lock(); try { return linkFirst(e); } finally { lock.unlock(); } } /** * @throws NullPointerException {@inheritDoc} */ public boolean offerLast(final E e) { if (e == null) { throw new NullPointerException(); } lock.lock(); try { return linkLast(e); } finally { lock.unlock(); } } /** * @throws NullPointerException {@inheritDoc} * @throws InterruptedException {@inheritDoc} */ public void putFirst(final E e) throws InterruptedException { if (e == null) { throw new NullPointerException(); } lock.lock(); try { while (!linkFirst(e)) { notFull.await(); } } finally { lock.unlock(); } } /** * @throws NullPointerException {@inheritDoc} * @throws InterruptedException {@inheritDoc} */ public void putLast(final E e) throws InterruptedException { if (e == null) { throw new NullPointerException(); } lock.lock(); try { while (!linkLast(e)) { notFull.await(); } } finally { lock.unlock(); } } /** * @throws NullPointerException {@inheritDoc} * @throws InterruptedException {@inheritDoc} */ public boolean offerFirst(final E e, final long timeout, final TimeUnit unit) throws InterruptedException { if (e == null) { throw new NullPointerException(); } long nanos = unit.toNanos(timeout); lock.lockInterruptibly(); try { for (;; ) { if (linkFirst(e)) { return true; } if (nanos <= 0) { return false; } nanos = notFull.awaitNanos(nanos); } } finally { lock.unlock(); } } /** * @throws NullPointerException {@inheritDoc} * @throws InterruptedException {@inheritDoc} */ public boolean offerLast(final E e, final long timeout, final TimeUnit unit) throws InterruptedException { if (e == null) { throw new NullPointerException(); } long nanos = unit.toNanos(timeout); lock.lockInterruptibly(); try { for (;; ) { if (linkLast(e)) { return true; } if (nanos <= 0) { return false; } nanos = notFull.awaitNanos(nanos); } } finally { lock.unlock(); } } /** * @throws NoSuchElementException {@inheritDoc} */ public E removeFirst() { final E x = pollFirst(); if (x == null) { throw new NoSuchElementException(); } return x; } /** * @throws NoSuchElementException {@inheritDoc} */ public E removeLast() { final E x = pollLast(); if (x == null) { throw new NoSuchElementException(); } return x; } public E pollFirst() { lock.lock(); try { return unlinkFirst(); } finally { lock.unlock(); } } public E pollLast() { lock.lock(); try { return unlinkLast(); } finally { lock.unlock(); } } public E takeFirst() throws InterruptedException { lock.lock(); try { E x; while ((x = unlinkFirst()) == null) { notEmpty.await(); } return x; } finally { lock.unlock(); } } public E takeLast() throws InterruptedException { lock.lock(); try { E x; while ((x = unlinkLast()) == null) { notEmpty.await(); } return x; } finally { lock.unlock(); } } public E pollFirst(final long timeout, final TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); lock.lockInterruptibly(); try { for (;; ) { final E x = unlinkFirst(); if (x != null) { return x; } if (nanos <= 0) { return null; } nanos = notEmpty.awaitNanos(nanos); } } finally { lock.unlock(); } } public E pollLast(final long timeout, final TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); lock.lockInterruptibly(); try { for (;; ) { final E x = unlinkLast(); if (x != null) { return x; } if (nanos <= 0) { return null; } nanos = notEmpty.awaitNanos(nanos); } } finally { lock.unlock(); } } /** * @throws NoSuchElementException {@inheritDoc} */ public E getFirst() { final E x = peekFirst(); if (x == null) { throw new NoSuchElementException(); } return x; } /** * @throws NoSuchElementException {@inheritDoc} */ public E getLast() { final E x = peekLast(); if (x == null) { throw new NoSuchElementException(); } return x; } public E peekFirst() { lock.lock(); try { return first == null ? null : first.item; } finally { lock.unlock(); } } public E peekLast() { lock.lock(); try { return last == null ? null : last.item; } finally { lock.unlock(); } } public boolean removeFirstOccurrence(final Object o) { if (o == null) { return false; } lock.lock(); try { for (Node<E> p = first; p != null; p = p.next) { if (o.equals(p.item)) { unlink(p); return true; } } return false; } finally { lock.unlock(); } } public boolean removeLastOccurrence(final Object o) { if (o == null) { return false; } lock.lock(); try { for (Node<E> p = last; p != null; p = p.prev) { if (o.equals(p.item)) { unlink(p); return true; } } return false; } finally { lock.unlock(); } } /** * Inserts the specified element at the end of this deque unless it would * violate capacity restrictions. When using a capacity-restricted deque, it * is generally preferable to use method {@link #offer(Object) offer}. * <p/> * <p/> * This method is equivalent to {@link #addLast}. * * @throws IllegalStateException if the element cannot be added at this time due to capacity * restrictions * @throws NullPointerException if the specified element is null */ @Override public boolean add(final E e) { addLast(e); return true; } // BlockingQueue methods /** * @throws NullPointerException if the specified element is null */ @Override public boolean offer(final E e) { return offerLast(e); } /** * @throws NullPointerException {@inheritDoc} * @throws InterruptedException {@inheritDoc} */ @Override public void put(final E e) throws InterruptedException { putLast(e); } /** * @throws NullPointerException {@inheritDoc} * @throws InterruptedException {@inheritDoc} */ @Override public boolean offer(final E e, final long timeout, final TimeUnit unit) throws InterruptedException { return offerLast(e, timeout, unit); } /** * Retrieves and removes the head of the queue represented by this deque. * This method differs from {@link #poll poll} only in that it throws an * exception if this deque is empty. * <p/> * <p/> * This method is equivalent to {@link #removeFirst() removeFirst}. * * @return the head of the queue represented by this deque * @throws NoSuchElementException if this deque is empty */ @Override public E remove() { return removeFirst(); } @Override public E poll() { return pollFirst(); } @Override public E take() throws InterruptedException { return takeFirst(); } @Override public E poll(final long timeout, final TimeUnit unit) throws InterruptedException { return pollFirst(timeout, unit); } /** * Retrieves, but does not remove, the head of the queue represented by this * deque. This method differs from {@link #peek peek} only in that it throws * an exception if this deque is empty. * <p/> * <p/> * This method is equivalent to {@link #getFirst() getFirst}. * * @return the head of the queue represented by this deque * @throws NoSuchElementException if this deque is empty */ @Override public E element() { return getFirst(); } @Override public E peek() { return peekFirst(); } /** * Returns the number of additional elements that this deque can ideally (in * the absence of memory or resource constraints) accept without blocking. * This is always equal to the initial capacity of this deque less the * current <tt>size</tt> of this deque. * <p/> * <p/> * Note that you <em>cannot</em> always tell if an attempt to insert an * element will succeed by inspecting <tt>remainingCapacity</tt> because it * may be the case that another thread is about to insert or remove an * element. */ @Override public int remainingCapacity() { lock.lock(); try { return capacity - count; } finally { lock.unlock(); } } /** * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ @Override public int drainTo(final Collection<? super E> c) { if (c == null) { throw new NullPointerException(); } if (c == this) { throw new IllegalArgumentException(); } lock.lock(); try { for (Node<E> p = first; p != null; p = p.next) { c.add(p.item); } final int n = count; count = 0; first = last = null; notFull.signalAll(); return n; } finally { lock.unlock(); } } /** * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ @Override public int drainTo(final Collection<? super E> c, final int maxElements) { if (c == null) { throw new NullPointerException(); } if (c == this) { throw new IllegalArgumentException(); } lock.lock(); try { int n = 0; while (n < maxElements && first != null) { c.add(first.item); first.prev = null; first = first.next; --count; ++n; } if (first == null) { last = null; } notFull.signalAll(); return n; } finally { lock.unlock(); } } /** * @throws IllegalStateException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public void push(final E e) { addFirst(e); } // Stack methods /** * @throws NoSuchElementException {@inheritDoc} */ public E pop() { return removeFirst(); } /** * Removes the first occurrence of the specified element from this deque. If * the deque does not contain the element, it is unchanged. More formally, * removes the first element <tt>e</tt> such that <tt>o.equals(e)</tt> (if * such an element exists). Returns <tt>true</tt> if this deque contained * the specified element (or equivalently, if this deque changed as a result * of the call). * <p/> * <p/> * This method is equivalent to {@link #removeFirstOccurrence(Object) * removeFirstOccurrence}. * * @param o element to be removed from this deque, if present * @return <tt>true</tt> if this deque changed as a result of the call */ @Override public boolean remove(final Object o) { return removeFirstOccurrence(o); } // Collection methods /** * Returns the number of elements in this deque. * * @return the number of elements in this deque */ @Override public int size() { lock.lock(); try { return count; } finally { lock.unlock(); } } /** * Returns <tt>true</tt> if this deque contains the specified element. More * formally, returns <tt>true</tt> if and only if this deque contains at * least one element <tt>e</tt> such that <tt>o.equals(e)</tt>. * * @param o object to be checked for containment in this deque * @return <tt>true</tt> if this deque contains the specified element */ @Override public boolean contains(final Object o) { if (o == null) { return false; } lock.lock(); try { for (Node<E> p = first; p != null; p = p.next) { if (o.equals(p.item)) { return true; } } return false; } finally { lock.unlock(); } } /** * Variant of removeFirstOccurrence needed by iterator.remove. Searches for * the node, not its contents. */ boolean removeNode(final Node<E> e) { lock.lock(); try { for (Node<E> p = first; p != null; p = p.next) { if (p == e) { unlink(p); return true; } } return false; } finally { lock.unlock(); } } /** * Returns an array containing all of the elements in this deque, in proper * sequence (from first to last element). * <p/> * <p/> * The returned array will be "safe" in that no references to it are * maintained by this deque. (In other words, this method must allocate a * new array). The caller is thus free to modify the returned array. * <p/> * <p/> * This method acts as bridge between array-based and collection-based APIs. * * @return an array containing all of the elements in this deque */ @Override public Object[] toArray() { lock.lock(); try { final Object[] a = new Object[count]; int k = 0; for (Node<E> p = first; p != null; p = p.next) { a[k++] = p.item; } return a; } finally { lock.unlock(); } } /** * Returns an array containing all of the elements in this deque, in proper * sequence; the runtime type of the returned array is that of the specified * array. If the deque fits in the specified array, it is returned therein. * Otherwise, a new array is allocated with the runtime type of the * specified array and the size of this deque. * <p/> * <p/> * If this deque fits in the specified array with room to spare (i.e., the * array has more elements than this deque), the element in the array * immediately following the end of the deque is set to <tt>null</tt>. * <p/> * <p/> * Like the {@link #toArray()} method, this method acts as bridge between * array-based and collection-based APIs. Further, this method allows * precise control over the runtime type of the output array, and may, under * certain circumstances, be used to save allocation costs. * <p/> * <p/> * Suppose <tt>x</tt> is a deque known to contain only strings. The * following code can be used to dump the deque into a newly allocated array * of <tt>String</tt>: * <p/> * <pre> * String[] y = x.toArray(new String[0]); * </pre> * <p/> * Note that <tt>toArray(new Object[0])</tt> is identical in function to * <tt>toArray()</tt>. * * @param a the array into which the elements of the deque are to be * stored, if it is big enough; otherwise, a new array of the * same runtime type is allocated for this purpose * @return an array containing all of the elements in this deque * @throws ArrayStoreException if the runtime type of the specified array is not a supertype * of the runtime type of every element in this deque * @throws NullPointerException if the specified array is null */ @SuppressWarnings("all") @Override public <T> T[] toArray(T[] a) { lock.lock(); try { if (a.length < count) { a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), count); } int k = 0; for (Node<E> p = first; p != null; p = p.next) { a[k++] = (T) p.item; } if (a.length > k) { a[k] = null; } return a; } finally { lock.unlock(); } } @Override public String toString() { lock.lock(); try { return super.toString(); } finally { lock.unlock(); } } /** * Atomically removes all of the elements from this deque. The deque will be * empty after this call returns. */ @Override public void clear() { lock.lock(); try { first = last = null; count = 0; notFull.signalAll(); } finally { lock.unlock(); } } /** * Returns an iterator over the elements in this deque in proper sequence. * The elements will be returned in order from first (head) to last (tail). * The returned <tt>Iterator</tt> is a "weakly consistent" iterator that * will never throw {@link ConcurrentModificationException}, and guarantees * to traverse elements as they existed upon construction of the iterator, * and may (but is not guaranteed to) reflect any modifications subsequent * to construction. * * @return an iterator over the elements in this deque in proper sequence */ @Override public Iterator<E> iterator() { return new Itr(); } /** * Returns an iterator over the elements in this deque in reverse sequential * order. The elements will be returned in order from last (tail) to first * (head). The returned <tt>Iterator</tt> is a "weakly consistent" iterator * that will never throw {@link ConcurrentModificationException}, and * guarantees to traverse elements as they existed upon construction of the * iterator, and may (but is not guaranteed to) reflect any modifications * subsequent to construction. */ public Iterator<E> descendingIterator() { return new DescendingItr(); } /** * Save the state of this deque to a stream (that is, serialize it). * * @param s the stream * @serialData The capacity (int), followed by elements (each an * <tt>Object</tt>) in the proper order, followed by a null */ private void writeObject(final java.io.ObjectOutputStream s) throws java.io.IOException { lock.lock(); try { // Write out capacity and any hidden stuff s.defaultWriteObject(); // Write out all elements in the proper order. for (Node<E> p = first; p != null; p = p.next) { s.writeObject(p.item); } // Use trailing null as sentinel s.writeObject(null); } finally { lock.unlock(); } } /** * Reconstitute this deque from a stream (that is, deserialize it). * * @param s the stream */ private void readObject(final java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); count = 0; first = null; last = null; // Read in all elements and place in queue for (;; ) { @SuppressWarnings("unchecked") final E item = (E) s.readObject(); if (item == null) { break; } add(item); } } /** * Doubly-linked list node class. */ static final class Node<E> { E item; Node<E> prev; Node<E> next; Node(final E x, final Node<E> p, final Node<E> n) { item = x; prev = p; next = n; } } /** * Base class for Iterators for LinkedBlockingDeque. */ private abstract class AbstractItr implements Iterator<E> { /** * The next node to return in next. */ Node<E> next; /** * nextItem holds on to item fields because once we claim that an * element exists in hasNext(), we must return item read under lock (in * advance()) even if it was in the process of being removed when * hasNext() was called. */ E nextItem; /** * Node returned by most recent call to next. Needed by remove. Reset to * null if this element is deleted by a call to remove. */ private Node<E> lastRet; AbstractItr() { advance(); // set to initial position } /** * Advances next, or if not yet initialized, sets to first node. * Implemented to move forward vs backward in the two subclasses. */ abstract void advance(); @Override public boolean hasNext() { return next != null; } @Override public E next() { if (next == null) { throw new NoSuchElementException(); } lastRet = next; final E x = nextItem; advance(); return x; } @Override public void remove() { final Node<E> n = lastRet; if (n == null) { throw new IllegalStateException(); } lastRet = null; // Note: removeNode rescans looking for this node to make // sure it was not already removed. Otherwise, trying to // re-remove could corrupt list. removeNode(n); } } /** * Forward iterator. */ private class Itr extends AbstractItr { @Override void advance() { final ReentrantLock lock = LinkedBlockingDeque.this.lock; lock.lock(); try { next = next == null ? first : next.next; nextItem = next == null ? null : next.item; } finally { lock.unlock(); } } } /** * Descending iterator for LinkedBlockingDeque. */ private class DescendingItr extends AbstractItr { @Override void advance() { final ReentrantLock lock = LinkedBlockingDeque.this.lock; lock.lock(); try { next = next == null ? last : next.prev; nextItem = next == null ? null : next.item; } finally { lock.unlock(); } } } }