content: package com58.zhl.concurrent;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Random;
  import java.util.concurrent.DelayQueue;
  import java.util.concurrent.Delayed;
  import java.util.concurrent.TimeUnit;
  import java.util.concurrent.atomic.AtomicInteger;
  import java.util.concurrent.atomic.AtomicLong;
  
  /**
   * 基于DelayQueue实现一个超时管理
   * @author 58_zhl
   *
   */
  public class Cpt8_TimeoutManager {
  	
  	private static List<String> result=new ArrayList<String>();
  	
  	/**
  	 * 遍历队列以便观察结果
  	 * @param queue
  	 */
  	private static String iteratorDelayQueue(DelayQueue<Session> queue){
  		Iterator<Session> it=queue.iterator();
  		StringBuilder sb=new StringBuilder();
  		while(it.hasNext()){
  			Session dt=it.next();
  			sb.append(dt.toString()+"\n");
  		}
  		return sb.toString();
  	}
  
  	
  	public static void testDelayQueue(){
  		DelayQueue<Session> queue=new DelayQueue<Session>();
  		Random random=new Random(47);
  		StringBuilder sb=new StringBuilder();
  		List<Session> list=new ArrayList<Session>();
  		//生产对象添加到队列中
  		for(int i=0;i<5;i++){
  			long timeout=(random.nextInt(10)+1)*1000;	//11以内的整数乘以1000毫秒
  			Session temp=new Session(timeout);
  			sb.append("id:"+temp.id+"-").append(timeout).append(" ");
  			list.add(temp);
  			queue.offer(temp);
  		}
  		System.out.println("=========================添加到队列中的顺序=========================");
  		System.out.println(sb.toString());
  		//可以先观察queue的排序结果
  		System.out.println("=========================队列中实际的顺序========================");
  		System.out.println(iteratorDelayQueue(queue));
  		System.out.println("=========================启动清理线程==============================");
  		monitorThread(queue);	//启动监控清理线程
  		//可先不执行延迟清理，进行观察
  		updateObject(list,queue);	//模拟因session最新被调用，而延迟清理
  	}
  	
  	public static void monitorThread(final DelayQueue<Session> queue){
  		Thread thread=new Thread(){
  			public void run(){
  				while(!queue.isEmpty()){
  					try {
  						Session dt=queue.take();
  						String str=dt.toString2()+"=====已被清理"+"\t currentTime:"+System.currentTimeMillis();
  						System.out.println(str);
  						result.add(str);
  						result.add(iteratorDelayQueue(queue));	//每次清理之后，都要保存一下队列的快照
  					} catch (InterruptedException e) { System.out.println("清理中断...."); return; }
  				}
  				System.out.println("清理完所有缓存！！！！！");
  				
  				System.out.println("======================延迟对象生命周期运行时queue的快照========================");
  				for(String tstr:result){
  					System.out.println(tstr);
  				}
  				System.out.println("==============================================");
  			}
  		};
  		thread.start();
  	}
  	
  	/**
  	 * 模拟在清理session池的时候，session因重新调用而导致清理时间延迟
  	 * @param list
  	 */
  	public static void updateObject(final List<Session> list,final DelayQueue<Session> queue){
  		Thread thread=new Thread(){
  			public void run(){
  				try {
  					//对于iteratorDelayQueue可能存在同步的问题，但是这里因sleep时间点的问题，不会发生异常
  					//暂时不需要处理
  					Thread.sleep(1000);	//睡眠1000ms
  					//list(4)默认生命周期是2000ms，睡眠1000后，现在应该还有1000ms左右
  					list.get(4).updateTriger();
  					result.add("id:"+list.get(4).id+" 寿命延长\t currentTime:"+System.currentTimeMillis());
  					Thread.sleep(1000);	//再次睡眠1000ms
  					//再次延长list(4)，这次延时后list(4)的总生命周期应该是4000ms
  					list.get(4).updateTriger();
  					result.add("id:"+list.get(4).id+" 寿命延长\t currentTime:"+System.currentTimeMillis());
  					//执行到此处时，一共睡眠了2000ms，list(1)的初始生命是6000ms,此时延迟应该总共生命周期为8000ms
  					list.get(1).updateTriger();
  					result.add("id:"+list.get(2).id+" 寿命延长\t currentTime:"+System.currentTimeMillis());
  				} catch (InterruptedException e) { }
  			}
  		};
  		thread.start();
  	}
  	
  	/**
  	 * 超时对象封装
  	 * @author 58_zhl
  	 *
  	 */
  	static class Session implements Delayed{
  		/**
  		 * 用于生成ID
  		 */
  		private static AtomicInteger objectId=new AtomicInteger(0);
  		/**
  		 * 本对象的ID
  		 */
  		private int id=objectId.incrementAndGet();	//注意与getAndIncrement方法的区别
  	    /**
  	     * 到期时间
  	     */
  	    private AtomicLong triger=null;
  	    /**
  	     * 创建时间
  	     */
  	    private long createTime=System.nanoTime();
  	    /**
  	     * 该对象被更新的次数
  	     */
  	    private AtomicInteger count=new AtomicInteger(0);
  	    /**
  	     * 该对象的超时时间，对象存在的生命周期
  	     */
  	    private final long timeout;
  	    
  	    public Session(long timeout){
  	    	this.timeout=TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS);	//保存对象
  	    	this.triger=new AtomicLong(createTime+this.timeout);	//对象的到期时间
  	    }
  	    
  	    /**
  	     * 更新超时时间，每使用某个对象时，应该调用此方法，
  	     * 来延长对象在内存的生命周期
  	     */
  	    public void updateTriger(){
  	    	/*
  	    	 * 统计被更新的次数，在对象创建后，因再次使用导致对象的生命周期延长的次数
  	    	 */
  	    	count.getAndIncrement();
  	    	long oldValue=0;	//获取当前值
  	    	long newValue=0;
  	    	do{
  	    		oldValue=triger.get();
  	    		newValue=System.nanoTime()+timeout;
  	    	}while(!triger.weakCompareAndSet(oldValue, newValue));
  	    }
  	    
  	    /**
  	     * 对比方法，按照从大到小的顺序
  	     * 在offer的时候只调用compareTo方法
  	     */
  		@Override
  		public int compareTo(Delayed o) {
  			Session dt=(Session)o;
  			System.out.println("compareTo()方法被调用....id:"+id+"\t currentTime:"+System.currentTimeMillis());
  			return (this.triger.get()>dt.triger.get()?1:(this.triger.get()<dt.triger.get()?-1:0));
  		}
  
  		/**
  		 * 返回与次对象相关的剩余延迟时间，注意，该方法和compareTo必须保持一致的排序
  		 * 离当前时间越远的时间，返回的值越大，这样与compareTo方法的排序结果保持一致
  		 * 
  		 * 在take的时候仅调用getDelay方法，但是compareTo方法将影响到新添加元素在队列
  		 * 中的位置，而这个位置可能决定getDelay方法的检索
  		 */
  		@Override
  		public long getDelay(TimeUnit unit) {
  			//unit是时间单位，如果triger中保存的不是unit单位的时间，则可以进行转换
  			//注意：这里一定要进行单位转换，只有这样才能达到最优的阻塞状态，而不是进行不停的循环
  			long remainTime=triger.get()-System.nanoTime();
  			System.out.println("id:"+id+"\tDelay:"+remainTime+" ns\tTimeUnit:"+unit.name());
  			return remainTime;
  		}
  		
  		public String toString() {
  			long start=createTime/1000000;
  			long end=triger.get() / 1000000;
  			return "id:" + id + "\t创建时间:" + start + " ms\t到期时间:" + end
  					+ " ms\t生命周期：" + (timeout / 1000000) + " ms";
  		}
  		
  		public String toString2(){
  			long start=createTime/1000000;
  			long end=triger.get() / 1000000;
  			return "id:"+id+"总寿命："+ (end-start)+" ms被更新的次数:"+ count.get();
  		}
  		
  	}
  	
  	
  	public static void main(String args[]){
  		
  		/**
  		 * DelayQueue内置封装了PriorityQueue。在进入take操作时，仅仅是在内置PriorityQueue对象上执行poll操作。
  		 * 实际上在DelayQueue中，是不会调用compareTo方法的，但是在每次offer元素到DelayQueue中时，首先将元素
  		 * 压入内置的PriorityQueue，然后判断当前压入到PriorityQueue的元素是否比压入当前元素之前的队列头元素
  		 * 还要小，如果还要小，则立刻执行available.signalAll();来唤醒DelayQueue的take操作。详情请参见代码实现
  		 * DelayQueue.take、DelayQueue.offer方法
  		 * 
  		 * PriorityQueue实现了弹出队列头部后的重排序操作，因PriorityQueue的重排序较复杂，因此我们仅需要知道每当
  		 * poll操作后，PriorityQueue都会对优先级队列进行重排序就可以了。但是如果队列头元素一直未能poll，则不会
  		 * 进行重排序。简单来说：PriorityQueue中的元素，一但成为头元素，那么它将不会再次成为中间节点。
  		 * 另外，PriorityQueue在offer的时候，也会插入到合适的位置并重排序，及使队列处于按优先级排序状态。
  		 */
  		
  		testDelayQueue();	//测试超时管理队列
  	}
  
  	/**
  	 * ====以下为运行结果简要说明
  	 * 
  	 *   compareTo()方法被调用....id:2	 currentTime:1387271463047
  	 *   compareTo()方法被调用....id:2	 currentTime:1387271463047
  	 *   compareTo()方法被调用....id:3	 currentTime:1387271463047
  	 *   compareTo()方法被调用....id:3	 currentTime:1387271463047
  	 *   compareTo()方法被调用....id:4	 currentTime:1387271463047
  	 *   compareTo()方法被调用....id:4	 currentTime:1387271463047
  	 *   compareTo()方法被调用....id:4	 currentTime:1387271463048
  	 *   compareTo()方法被调用....id:5	 currentTime:1387271463048
  	 *   compareTo()方法被调用....id:5	 currentTime:1387271463048
  	 *   compareTo()方法被调用....id:5	 currentTime:1387271463048
  	 *   =========================添加到队列中的顺序=========================
  	 *   id:1-9000 id:2-6000 id:3-4000 id:4-2000 id:5-2000 
  	 *   =========================队列中实际的顺序========================
  	 *   id:4	创建时间:95280919 ms	到期时间:95282919 ms	生命周期：2000 ms
  	 *   id:5	创建时间:95280919 ms	到期时间:95282919 ms	生命周期：2000 ms
  	 *   id:2	创建时间:95280918 ms	到期时间:95286918 ms	生命周期：6000 ms
  	 *   id:1	创建时间:95280917 ms	到期时间:95289917 ms	生命周期：9000 ms
  	 *   id:3	创建时间:95280918 ms	到期时间:95284918 ms	生命周期：4000 ms
  	 *   
  	 *   =========================启动清理线程==============================
  	 *   id:4	Delay:1998754758 ns	TimeUnit:NANOSECONDS	// TODO 第一次排序后，启动线程发现需要堵塞1998754758纳秒
  	 *   id:4	Delay:-383338 ns	TimeUnit:NANOSECONDS	// TODO 当堵塞指定时间后立刻调用getDelay方法，发现返回值小于0，立刻弹出
  	 *   compareTo()方法被调用....id:5	 currentTime:1387271465049	//弹出过程中，还会进行重排序
  	 *   compareTo()方法被调用....id:3	 currentTime:1387271465049
  	 *   compareTo()方法被调用....id:3	 currentTime:1387271465049
  	 *   id:4总寿命：2000 ms被更新的次数:0=====已被清理	 currentTime:1387271465049
  	 *   id:5	Delay:1000503689 ns	TimeUnit:NANOSECONDS
  	 *   id:5	Delay:998916441 ns	TimeUnit:NANOSECONDS
  	 *   id:5	Delay:-1077481 ns	TimeUnit:NANOSECONDS
  	 *   compareTo()方法被调用....id:3	 currentTime:1387271467051
  	 *   compareTo()方法被调用....id:1	 currentTime:1387271467051
  	 *   id:5总寿命：4001 ms被更新的次数:2=====已被清理	 currentTime:1387271467051
  	 *   id:3	Delay:-2868151 ns	TimeUnit:NANOSECONDS
  	 *   compareTo()方法被调用....id:2	 currentTime:1387271467051
  	 *   id:3总寿命：4000 ms被更新的次数:0=====已被清理	 currentTime:1387271467051
  	 *   id:2	Delay:3998453678 ns	TimeUnit:NANOSECONDS
  	 *   id:2	Delay:-194911 ns	TimeUnit:NANOSECONDS
  	 *   id:2总寿命：8002 ms被更新的次数:1=====已被清理	 currentTime:1387271471050
  	 *   id:1	Delay:996749726 ns	TimeUnit:NANOSECONDS
  	 *   id:1	Delay:-1034123 ns	TimeUnit:NANOSECONDS
  	 *   id:1总寿命：9000 ms被更新的次数:0=====已被清理	 currentTime:1387271472048
  	 *   清理完所有缓存！！！！！
  	 *   ======================延迟对象生命周期运行时queue的快照========================
  	 *   id:5 寿命延长	 currentTime:1387271464049   //TODO 寿命虽然延长了，但是不能立刻生效，因为只有等到第一个take元素弹出后，才有机会进行重排序
  	 *   id:4总寿命：2000 ms被更新的次数:0=====已被清理	 currentTime:1387271465049	//TODO 第一个元素弹出了
  	 *   id:5	创建时间:95280919 ms	到期时间:95283920 ms	生命周期：2000 ms	//TODO 这是弹出后，并且重排序之后的结果
  	 *   id:3	创建时间:95280918 ms	到期时间:95284918 ms	生命周期：4000 ms
  	 *   id:2	创建时间:95280918 ms	到期时间:95286918 ms	生命周期：6000 ms
  	 *   id:1	创建时间:95280917 ms	到期时间:95289917 ms	生命周期：9000 ms
  	 *   
  	 *   id:5 寿命延长	 currentTime:1387271465050
  	 *   id:3 寿命延长	 currentTime:1387271465050
  	 *   id:5总寿命：4001 ms被更新的次数:2=====已被清理	 currentTime:1387271467051
  	 *   id:3	创建时间:95280918 ms	到期时间:95284918 ms	生命周期：4000 ms
  	 *   id:1	创建时间:95280917 ms	到期时间:95289917 ms	生命周期：9000 ms
  	 *   id:2	创建时间:95280918 ms	到期时间:95288920 ms	生命周期：6000 ms
  	 *   
  	 *   id:3总寿命：4000 ms被更新的次数:0=====已被清理	 currentTime:1387271467051
  	 *   id:2	创建时间:95280918 ms	到期时间:95288920 ms	生命周期：6000 ms
  	 *   id:1	创建时间:95280917 ms	到期时间:95289917 ms	生命周期：9000 ms
  	 *   
  	 *   id:2总寿命：8002 ms被更新的次数:1=====已被清理	 currentTime:1387271471050
  	 *   id:1	创建时间:95280917 ms	到期时间:95289917 ms	生命周期：9000 ms
  	 *   
  	 *   id:1总寿命：9000 ms被更新的次数:0=====已被清理	 currentTime:1387271472048
  	 *   
  	 *   ==============================================
  	 */
  	
  }
  