/**
*
*/
package com.taobao.top.analysis.util;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 放入事件用于检测是否超时,先做成比较简化版的实现,后续可以扩展
* @author fangweng
* @email: fangweng@taobao.com
* 2011-12-5 下午1:37:00
*
*/
public abstract class TimeOutQueue<E extends TimeOutEvent>{
private static final Log logger = LogFactory.getLog(TimeOutQueue.class);
private PriorityBlockingQueue<E> taskEventPool;//等待状态变更的消息池
private TimeOutChecker timeOutChecker;//后台检查消息变更资源池的线程
private Semaphore poolIsEmpty = new Semaphore(1);//防止空循环检查消息变更资源池
//这三个用于超时事件队列检查
private ReentrantLock lock;
private Condition checkCondition;
private AtomicLong minTimeOutStamp;
public TimeOutQueue()
{
lock = new ReentrantLock();
checkCondition = lock.newCondition();
minTimeOutStamp = new AtomicLong(0);
taskEventPool = new PriorityBlockingQueue<E>(100);
timeOutChecker = new TimeOutChecker();
timeOutChecker.setDaemon(true);
timeOutChecker.start();
}
public void release()
{
clean();
if (timeOutChecker != null)
timeOutChecker.stopThread();
}
public void clean()
{
if (taskEventPool != null)
taskEventPool.clear();
minTimeOutStamp.set(0);
}
/**
* 用于后台检查状态变更消息池,当前只负责Timeout状态检查
* @author fangweng
* @email fangweng@taobao.com
* @date 2011-5-17
*
*/
class TimeOutChecker extends Thread
{
public TimeOutChecker()
{
super("TimeOutChecker-thread");
}
boolean isRunning = true;
public void run()
{
try
{
while(isRunning)
{
//checker没有竞争,所以这里还是可靠的,用于防止内部没有任何数据的空转
poolIsEmpty.acquire();
if (taskEventPool.isEmpty())
continue;
E node;
long restTime = 0;
while((node = taskEventPool.peek()) != null)
{
restTime = node.getEventCreateTime() + node.getMaxEventHoldTime() * 1000 - System.currentTimeMillis();
if (node.getEventCreateTime() != 0 && restTime <= 0)
{
taskEventPool.poll();
timeOutAction(node);
}
else
{
if (node.getEventCreateTime() == 0)
restTime = 5 * 60 * 1000;//如果剩下的都没有超时事件了,则给5分钟
break;
}
}
//cpu time interval ,预估一下一个最小超时到来的情况,防止多次循环
if (restTime > 10)
{
if (restTime > 5 * 60 * 1000)
{
if (logger.isInfoEnabled())
logger.info("restTime : " + restTime + " so large.");
restTime = 5 * 60 * 1000;
}
boolean flag = lock.tryLock();
try
{
if (flag)
checkCondition.await(restTime, TimeUnit.MILLISECONDS);
}
catch(InterruptedException ie)
{
//do nothing
}
catch(Exception ex)
{
logger.error(ex,ex);
}
finally
{
if (flag)
lock.unlock();
}
}
poolIsEmpty.release();
}
}
catch (InterruptedException e)
{
//do nothing
}
catch(Exception ex)
{
logger.error("TaskChecker end...",ex);
}
}
public void stopThread()
{
isRunning = false;
interrupt();
}
}
/**
* 当有新的事件加入状态变更等待队列,
* 判断最小的timeout是否发生改变,选择性唤醒checker
* @param node
*/
public void eventChainChange(E node)
{
if (node.getEventCreateTime() > 0 && (minTimeOutStamp.get() == 0 || node.getEventCreateTime() < minTimeOutStamp.get()))
{
//不做并发控制
minTimeOutStamp.set(node.getEventCreateTime());
boolean flag = lock.tryLock();
try
{
if (flag)
{
checkCondition.signalAll();
}
}
catch(Exception ex)
{
logger.error(ex,ex);
}
finally
{
if (flag)
lock.unlock();
}
}
}
public void clear() {
taskEventPool.clear();
if (poolIsEmpty.availablePermits() == 0)
poolIsEmpty.release();
}
public boolean contains(Object o) {
return taskEventPool.contains(o);
}
public boolean isEmpty() {
return taskEventPool.isEmpty();
}
public boolean remove(Object o) {
return taskEventPool.remove(o);
}
public int size() {
return taskEventPool.size();
}
public boolean add(E e) {
boolean result = taskEventPool.add(e);
if (result)
{
eventChainChange(e);
if (poolIsEmpty.availablePermits() == 0)
poolIsEmpty.release();
}
return result;
}
public boolean offer(E e) {
boolean result = taskEventPool.offer(e);
if (result)
{
eventChainChange(e);
if (poolIsEmpty.availablePermits() == 0)
poolIsEmpty.release();
}
return result;
}
public E peek() {
return taskEventPool.peek();
}
public E poll() {
return taskEventPool.poll();
}
//需要对timeout做一些反应
public abstract void timeOutAction(E event);
}