package org.opensource.clearpool.core.chain; import java.lang.reflect.Field; import java.util.concurrent.atomic.AtomicInteger; import org.opensource.clearpool.exception.ConnectionPoolException; import org.opensource.clearpool.logging.PoolLogger; import org.opensource.clearpool.logging.PoolLoggerFactory; import sun.misc.Unsafe; /** * This is a one-way chain,it is provide atomic operation like {@link #add(E)}, {@link #get} and * getIdle(long). * * Note:the class used {@link Unsafe} by reflection.We should know that {@link Unsafe} is not * encouraged to use. * * @author xionghui * @date 26.07.2014 * @version 1.0 */ @SuppressWarnings("restriction") @Deprecated public class AtomicSingleChain<E> extends CommonChain<E> { private static final PoolLogger LOGGER = PoolLoggerFactory.getLogger(AtomicSingleChain.class); private static final Unsafe UNSAFE; private static final long HEAD_OFFSET; private static final long TAIL_OFFSET; static { try { Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); unsafeField.setAccessible(true); UNSAFE = (Unsafe) unsafeField.get(null); HEAD_OFFSET = UNSAFE.objectFieldOffset(AtomicSingleChain.class.getDeclaredField("head")); TAIL_OFFSET = UNSAFE.objectFieldOffset(AtomicSingleChain.class.getDeclaredField("tail")); } catch (Exception e) { LOGGER.error("init failed: ", e); throw new ConnectionPoolException("use Unsafe error"); } } private volatile Node<E> head = this.tail = new SingleNode<E>(null); private volatile Node<E> tail; protected AtomicInteger size = new AtomicInteger(); /** * Add a element to {@link #tail} atomically. */ @Override public void add(E e) { Node<E> update = new SingleNode<E>(e); for (;;) { Node<E> current = this.tail; if (this.compareAndSetTail(current, update)) { update.entryTime = System.currentTimeMillis(); current.next = update; this.size.getAndIncrement(); return; } } } /** * Remove a element from {@link #head} atomically. */ @Override public E remove() { for (;;) { Node<E> current = this.head; Node<E> update = current.next; if (update == null && current == this.head) { E element = current.getElement(); if (element != null) { this.size.getAndDecrement(); return element; } else if (this.size.get() == 0) { // in case the pool grow so fast return null; } } else if (this.compareAndSetHead(current, update)) { // help gc current.next = null; E element = current.getElement(); if (element != null) { this.size.getAndDecrement(); return element; } } } } /** * Remove a element which is overtime from {@link #head} atomically. */ @Override public E removeIdle(long period) { for (;;) { Node<E> current = this.head; long now = System.currentTimeMillis(); if (now - current.entryTime < period) { return null; } Node<E> update = current.next; if (update == null && current == this.head) { E element = current.getElement(); if (element != null) { this.size.getAndDecrement(); } return element; } else if (this.compareAndSetHead(current, update)) { // help gc E element = current.getElement(); if (element != null) { this.size.getAndDecrement(); return element; } } } } /** * Atomically sets the Node to the given updated Node if the current Node is the expected Node. * * @param expect the expected Node * @param update the new Node * @return true if successful. False return indicates that the actual Node was not equal to the * expected Node. */ private boolean compareAndSetHead(Node<E> expect, Node<E> update) { return UNSAFE.compareAndSwapObject(this, HEAD_OFFSET, expect, update); } /** * @see {@link #compareAndSetHead(Node,Node)} */ private boolean compareAndSetTail(Node<E> expect, Node<E> update) { return UNSAFE.compareAndSwapObject(this, TAIL_OFFSET, expect, update); } @Override public int size() { return this.size.get(); } /** * This class used to get element atomically. * * @author xionghui * @date 26.07.2014 * @version 1.0 */ private final static class SingleNode<E> extends Node<E> { private static final PoolLogger LOGGER = PoolLoggerFactory.getLogger(SingleNode.class); private static final long ELEMENT_OFFSET; static { try { ELEMENT_OFFSET = UNSAFE.objectFieldOffset(Node.class.getDeclaredField("element")); } catch (Exception e) { LOGGER.error("init ELEMENT_OFFSET error: ", e); throw new ConnectionPoolException("get element position error"); } } SingleNode(E element) { super(element); } @Override E getElement() { for (;;) { E current = element; if (this.compareAndSetElement(current, null)) { return current; } } } @Override void setNext(Node<E> next) { this.next = next; } /** * @see {@link #compareAndSetHead(Node,Node)} */ boolean compareAndSetElement(E expect, E update) { return UNSAFE.compareAndSwapObject(this, ELEMENT_OFFSET, expect, update); } } }