Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.util.AbstractQueue;
- import java.util.Iterator;
- import java.util.NoSuchElementException;
- import java.util.concurrent.Callable;
- import java.util.concurrent.atomic.AtomicReference;
- /**
- * Concurrent stack, useful for implementing pools since the recently added data is more likely to be in the memory cache
- * Cache-hits are good.
- *
- * The pool creates new objects in case it cannot satisfy the pool request by an existing element.
- * The current version is NOT serializable and doesn't support null elements.
- *
- *
- * @author Stanimir Simeonoff
- * @version 1.1
- * @param <E> The desired pooled type
- */
- public class ConcurrentLinkedPool<E> extends AbstractQueue<E>{
- final int maxSize;
- final Callable<E> creator;
- private static class Node<E> extends AtomicReference<E>{
- private static final long serialVersionUID = -2678632089894452271L;
- //extend AtomicReference instead AtomicFieldUpdater, much simpler and cleaner
- Node next;
- int size;
- Node(E value){
- lazySet(value);
- }
- }
- private final AtomicReference<Node> head=new AtomicReference<Node>();
- public ConcurrentLinkedPool(int maxSize, Callable<E> creator){
- if (maxSize<1)
- throw new IllegalArgumentException("size too low");
- this.maxSize = maxSize;
- this.creator = creator;
- }
- public static <T> ConcurrentLinkedPool<T> newInstance(Class<T> clazz){
- return new ConcurrentLinkedPool<T>(ConcurrentArrayPool.CPUs*2, ConcurrentArrayPool.newCallable(clazz));
- }
- protected E newInstance(){
- try {
- return creator.call();
- } catch (Exception e) {
- throw new RuntimeException("failed create instance", e);
- }
- }
- /**
- * the size is atomically updated with the head of the stack and usually it's correct.
- * However, the size is not immediately updated if a node is removed from the middle of the stack
- * until it's relinked by a poll() operation
- * @return current size
- */
- public int size(){
- Node n = head.get();
- return n==null?0:n.size;
- }
- /**
- * the method never returns null unless newInstance returns so
- * @return the head of stack or a newly creaed instance via newInstance
- */
- public E poll(){
- for(;;){
- final Node<E> node = head.get();
- if (node==null){
- return newInstance();
- }
- final E result = node.get();
- if (head.compareAndSet(node, node.next)){
- if (result!=null){
- return result;
- }
- }
- }
- }
- /**
- * Offers the element to the pool. The method ignores null elements.
- * @return true, if successful (i.e. below the capcity), false otheriwse
- */
- public boolean offer(E e){
- if (e==null)
- return false;//silently ignore nulls
- final Node h=new Node(e);
- for(;;){
- Node<E> node = head.get();
- int size = node!=null?node.size:0;
- if (size>=maxSize)
- return false;
- h.next = node;
- h.size = size+1;
- if (head.compareAndSet(node, h)){
- return true;
- }
- }
- }
- public boolean isEmpty(){
- return head.get()==null;//should be peek()!=null but meh
- }
- public void clear() {
- head.set(null);
- }
- public E peek(){
- for(;;){
- Node<E> node = head.get();
- if (node==null){
- return null;
- }
- E value = node.get();
- if (value!=null)
- return value;
- head.compareAndSet(node, node.next);
- }
- }
- /**
- * Provides an ad-hoc possibility to introduce custom equals impl. for instance just ==
- * @param object - the object passed to methods like contains, remove, etc
- * @param element - already existing object in the stack
- * @return true if the object equals the element, false otherwise
- */
- protected boolean equals(Object object, E element){
- return object==element || object.equals(element);
- }
- /**
- * Removes an element from the pool.
- * Note: the size will not be updated immediately.
- * @param o Element to be removed
- * @return true if the pool has been modified, false otherwise; it might return true if another thread is removing the same element
- */
- public boolean remove(Object o){
- for(Node<E> node = head.get();node!=null;node=node.next){
- E value = node.get();
- if (equals(o, value)){
- return node.compareAndSet(value, null);
- }
- }
- return false;
- }
- public boolean contains(Object o){
- if (o==null)
- return false;
- for(Node<E> node = head.get();node!=null;node=node.next){
- E value = node.get();
- if (equals(o, value)){
- return true;
- }
- }
- return false;
- }
- public Iterator<E> iterator(){
- return new Itr();
- }
- private class Itr implements Iterator<E> {//stolen from ConcurrentLinkedQueue
- /**
- * Next node to return item for.
- */
- private Node<E> nextNode;
- /**
- * nextItem holds on to item fields because once we claim
- * that an element exists in hasNext(), we must return it in
- * the following next() call even if it was in the process of
- * being removed when hasNext() was called.
- */
- private E nextItem;
- /**
- * Node of the last returned item, to support remove.
- */
- private Node<E> lastRet;
- Itr() {
- advance();
- }
- /**
- * Moves to next valid node and returns item to return for
- * next(), or null if no such.
- */
- private E advance() {
- lastRet = nextNode;
- E x = nextItem;
- Node<E> p = (nextNode == null)? head.get() : nextNode.next;
- for (;;) {
- if (p == null) {
- nextNode = null;
- nextItem = null;
- return x;
- }
- E item = p.get();
- if (item != null) {
- nextNode = p;
- nextItem = item;
- return x;
- } else // skip nulls
- p = p.next;
- }
- }
- public boolean hasNext() {
- return nextNode != null;
- }
- public E next() {
- if (nextNode == null) throw new NoSuchElementException();
- return advance();
- }
- public void remove() {
- Node<E> l = lastRet;
- if (l == null) throw new IllegalStateException();
- // rely on a future traversal to relink.
- l.set(null);
- lastRet = null;
- if (l==head.get()) head.compareAndSet(l, l.next);//unlink the head immediately
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement