package com.chamago.bison.queue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
*
* @author Gavin.peng
*
* 2013-10-15 下午12:20:26
× bison
*/
public class LinkListQueue<E>
{
private final AtomicInteger count = new AtomicInteger(0);
private transient Node<E> head;
private transient Node<E> last;
private final ReentrantLock takeLock = new ReentrantLock();
private final Condition notEmpty = this.takeLock.newCondition();
private final ReentrantLock putLock = new ReentrantLock();
private void signalNotEmpty()
{
ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
this.notEmpty.signal();
} finally {
takeLock.unlock();
}
}
private void insert(E x)
{
this.last = (this.last.next = new Node(x));
}
private E extract()
{
Node<E> first = this.head.next;
this.head = null;
this.head = first;
E x = first.item;
first.item = null;
this.head.item = null;
first = null;
return x;
}
private void fullyLock()
{
this.putLock.lock();
this.takeLock.lock();
}
private void fullyUnlock()
{
this.takeLock.unlock();
this.putLock.unlock();
}
public LinkListQueue()
{
this.last = (this.head = new Node(null));
}
public int size()
{
return this.count.get();
}
public boolean offer(E o)
{
if (o == null) throw new NullPointerException();
int c = -1;
ReentrantLock putLock = this.putLock;
AtomicInteger count = this.count;
putLock.lock();
try {
insert(o);
c = count.getAndIncrement();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return c >= 0;
}
public E take() throws InterruptedException { int c = -1;
AtomicInteger count = this.count;
ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
E x;
try {
try {
while (count.get() == 0)
this.notEmpty.await();
} catch (InterruptedException ie) {
this.notEmpty.signal();
throw ie;
}
x = extract();
c = count.getAndDecrement();
if (c > 1)
this.notEmpty.signal();
} finally {
takeLock.unlock();
}
return x;
}
public void clear()
{
fullyLock();
try {
this.head.next = null;
assert (this.head.item == null);
this.last = this.head;
} finally {
fullyUnlock();
}
}
static class Node<E>
{
volatile E item;
Node<E> next;
Node(E x)
{
this.item = x;
}
}
}