CometHashMap という名前が良いか?

UDP受信のように、同じデータが短い時間間隔で送られてくる可能性がある
場合の受け側で、1回だけを検出して処理する方法を考える。
当初、タイマー付きMapみたいなことを考えたが、マップに格納した要素
1つ1つにタイマースレッドを作成するのは危険だ。
そこで、Key と時刻のマップを内部で持ち、SortedMap#headMap を利用して
remove の実行、チェックしての任意の処理実行を考えた。

public interface CometMapper<K,V>{
   public void checkIn(K key,V value);
}
----------------------------------------------------
import java.util.Calendar;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeMap;
import java.util.Map.Entry;
import com.google.inject.Inject;
/**
 * CometHashMap.
 * 任意の時間間隔で要素が削除される HashMap
 * put実行時 containsKey の結果が false の時に任意の処理を実行する。
 * コンストラクタで任意の時間間隔 msec と 
 * 任意の処理メソッドインスタンスを指定する。
 */

public class CometHashMap<K,V> extends HashMap<K,V>{
   private static final long serialVersionUID = 1L;
   private Timer timer;
   private CometMapper mapper;
   long checkTime;
   Map<String,Long> hmap;
   /**
    * @param checkTime 削除する時間間隔 msec
    * @param mapper 任意の処理
    */

   @Inject
   public CometHashMap(@CometLiveScorp long checkTime,CometMapper mapper){
      super();
      this.hmap = new HashMap<String,Long>();
      this.mapper = mapper;
      this.timer = new Timer("CometHashMap");
      this.checkTime = checkTime;
      Calendar cal = Calendar.getInstance();
      cal.add(Calendar.SECOND,1);
      cal.clear(Calendar.MILLISECOND);

      this.timer.scheduleAtFixedRate(new _Reseter(),cal.getTime(),checkTime);
   }

   /*
    * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
    */

   @Override
   public V put(K key,V value){
      return this._put(key,value);
   }
   @SuppressWarnings("unchecked")
   private synchronized V _put(K key,V value){
      this.hmap.put(key.toString(),System.currentTimeMillis());
      boolean b = super.containsKey(key) ? false : true;
      V v = super.put(key,value);
      if (b) this.mapper.checkIn(key,value);
      return v;
   }


   class _Reseter extends TimerTask{
      private SortedMap<Long,String> smap;
      _Reseter(){
         this.smap = new TreeMap<Long,String>(
            new Comparator<Long>(){
               @Override
               public int compare(Long l1,Long l2){
                  return l1.compareTo(l2) >= 0 ? 1 : -1;
               }
            }
         );
      }
      /*
       * @see java.util.TimerTask#run()
       */

      @Override
      public void run(){
         if (CometHashMap.this.hmap.size()==0) return;
         this.smap.clear();
         for(Entry<String,Long> e : CometHashMap.this.hmap.entrySet()){
            this.smap.put(e.getValue(),e.getKey());
         }
         for(String key : this.smap.headMap(System.currentTimeMillis() - CometHashMap.this.checkTime).values()){
            CometHashMap.this.hmap.remove(key);
            CometHashMap.this.remove(key);
         }
      }

   }
   /**
    * GC実行より確実に内部で処理されるマップを削除するタイマーを
    * キャンセルさせるために用意した終了処理
    */

   public void close(){
      try{
      this.finalize();
      }catch(Throwable e){
      }finally{
         this.timer.cancel();
      }
   }
   /*
    * @see java.lang.Object#finalize()
    */
   @Override
   protected void finalize() throws Throwable{
      this.timer.cancel();
      super.finalize();
   }
}