import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

import sun.misc.Unsafe;
public class FastObjectPool<T> {  
    private Holder<T>[] objects;  
    private volatile int takePointer;  
    private int releasePointer;  
    private final int mask;  
    private final long BASE;  
    private final long INDEXSCALE;  
    private final long ASHIFT;  
    public ReentrantLock lock = new ReentrantLock();  
    private ThreadLocal<Holder<T>> localValue = new ThreadLocal<Holder<T>>();  
    @SuppressWarnings({ "unchecked", "restriction" })  
    public FastObjectPool(PoolFactory<T> factory, int size) {  
  
        int newSize = 1;  
        while (newSize < size) {  
            newSize = newSize << 1;  
        }  
        size = newSize;  
        objects = new Holder[size];  
        for (int x = 0; x < size; x++) {  
            objects[x] = new Holder<T>(factory.create());  
        }  
        mask = size - 1;  
        releasePointer = size;  
        BASE = THE_UNSAFE.arrayBaseOffset(Holder[].class);  
        INDEXSCALE = THE_UNSAFE.arrayIndexScale(Holder[].class);  
        ASHIFT = 31 - Integer.numberOfLeadingZeros((int) INDEXSCALE);  
    }  
  
    @SuppressWarnings("restriction")
	public Holder<T> take() {  
        int localTakePointer;  
  
        Holder<T> localObject = localValue.get();  
        if (localObject != null) {  
            if (localObject.state.compareAndSet(Holder.FREE, Holder.USED)) {  
                return localObject;  
            }  
        }  
  
        while (releasePointer != (localTakePointer = takePointer)) {  
            int index = localTakePointer & mask;  
            Holder<T> holder = objects[index];  
            // if(holder!=null && THE_UNSAFE.compareAndSwapObject(objects,  
            // (index*INDEXSCALE)+BASE, holder, null))  
            if (holder != null  
                    && THE_UNSAFE.compareAndSwapObject(objects,  
                            (index << ASHIFT) + BASE, holder, null)) {  
                takePointer = localTakePointer + 1;  
                if (holder.state.compareAndSet(Holder.FREE, Holder.USED)) {  
                    localValue.set(holder);  
                    return holder;  
                }  
            }  
        }  
        return null;  
    }  
  
    @SuppressWarnings("restriction")
	public void release(Holder<T> object) throws InterruptedException {  
        lock.lockInterruptibly();  
        try {  
            int localValue = releasePointer;  
            // long index = ((localValue & mask) * INDEXSCALE ) + BASE;  
            long index = ((localValue & mask) << ASHIFT) + BASE;  
            if (object.state.compareAndSet(Holder.USED, Holder.FREE)) {  
                THE_UNSAFE.putOrderedObject(objects, index, object);  
                releasePointer = localValue + 1;  
            } else {  
                throw new IllegalArgumentException("Invalid reference passed");  
            }  
        } finally {  
            lock.unlock();  
        }  
    } 
    
    public static class Holder<T> {  
        private T value;  
        public static final int FREE = 0;  
        public static final int USED = 1;  
  
        private AtomicInteger state = new AtomicInteger(FREE);  
  
        public Holder(T value) {  
            this.value = value;  
        }  
  
        public T getValue() {  
            return value;  
        }  
    }  
    
    public static interface PoolFactory<T> {  
        public T create();  
    }  
    
    @SuppressWarnings("restriction")
	public static final Unsafe THE_UNSAFE;  
    static {  
        try {  
            final PrivilegedExceptionAction<Unsafe> action = new PrivilegedExceptionAction<Unsafe>() {  
                public Unsafe run() throws Exception {  
					Field theUnsafe = Unsafe.class  
                            .getDeclaredField("theUnsafe");  
                    theUnsafe.setAccessible(true);  
                    return (Unsafe) theUnsafe.get(null);  
                }  
            };  
  
            THE_UNSAFE = AccessController.doPrivileged(action);  
        } catch (Exception e) {  
            throw new RuntimeException("Unable to load unsafe", e);  
        }  
    } 
}