一、前言
基于mina-core(2.0.4)包中实现的org.apache.mina.util.ExpiringMap实现自定义失效超时Map,用户大数据缓存策略、用户会话超时及有效时间限制等场景,具体源码内容如下所示
二、源码说明
package org.apache.mina.util;@b@@b@import java.util.Collection;@b@import java.util.Iterator;@b@import java.util.Map;@b@import java.util.Map.Entry;@b@import java.util.Set;@b@import java.util.concurrent.ConcurrentHashMap;@b@import java.util.concurrent.CopyOnWriteArrayList;@b@import java.util.concurrent.locks.Lock;@b@import java.util.concurrent.locks.ReadWriteLock;@b@import java.util.concurrent.locks.ReentrantReadWriteLock;@b@@b@public class ExpiringMap<K, V>@b@ implements Map<K, V>@b@{@b@ public static final int DEFAULT_TIME_TO_LIVE = 60;@b@ public static final int DEFAULT_EXPIRATION_INTERVAL = 1;@b@ private static volatile int expirerCount = 1;@b@ private final ConcurrentHashMap<K, ExpiringMap<K, V>.ExpiringObject> delegate;@b@ private final CopyOnWriteArrayList<ExpirationListener<V>> expirationListeners;@b@ private final ExpiringMap<K, V>.Expirer expirer;@b@@b@ public ExpiringMap()@b@ {@b@ this(60, 1);@b@ }@b@@b@ public ExpiringMap(int timeToLive)@b@ {@b@ this(timeToLive, 1);@b@ }@b@@b@ public ExpiringMap(int timeToLive, int expirationInterval)@b@ {@b@ this(new ConcurrentHashMap(), new CopyOnWriteArrayList(), timeToLive, expirationInterval);@b@ }@b@@b@ private ExpiringMap(ConcurrentHashMap<K, ExpiringMap<K, V>.ExpiringObject> delegate, CopyOnWriteArrayList<ExpirationListener<V>> expirationListeners, int timeToLive, int expirationInterval)@b@ {@b@ this.delegate = delegate;@b@ this.expirationListeners = expirationListeners;@b@@b@ this.expirer = new Expirer(this);@b@ this.expirer.setTimeToLive(timeToLive);@b@ this.expirer.setExpirationInterval(expirationInterval);@b@ }@b@@b@ public V put(K key, V value) {@b@ ExpiringObject answer = (ExpiringObject)this.delegate.put(key, new ExpiringObject(this, key, value, System.currentTimeMillis()));@b@@b@ if (answer == null) {@b@ return null;@b@ }@b@@b@ return answer.getValue();@b@ }@b@@b@ public V get(Object key) {@b@ ExpiringObject object = (ExpiringObject)this.delegate.get(key);@b@@b@ if (object != null) {@b@ object.setLastAccessTime(System.currentTimeMillis());@b@@b@ return object.getValue();@b@ }@b@@b@ return null;@b@ }@b@@b@ public V remove(Object key) {@b@ ExpiringObject answer = (ExpiringObject)this.delegate.remove(key);@b@ if (answer == null) {@b@ return null;@b@ }@b@@b@ return answer.getValue();@b@ }@b@@b@ public boolean containsKey(Object key) {@b@ return this.delegate.containsKey(key);@b@ }@b@@b@ public boolean containsValue(Object value) {@b@ return this.delegate.containsValue(value);@b@ }@b@@b@ public int size() {@b@ return this.delegate.size();@b@ }@b@@b@ public boolean isEmpty() {@b@ return this.delegate.isEmpty();@b@ }@b@@b@ public void clear() {@b@ this.delegate.clear();@b@ }@b@@b@ public int hashCode()@b@ {@b@ return this.delegate.hashCode();@b@ }@b@@b@ public Set<K> keySet() {@b@ return this.delegate.keySet();@b@ }@b@@b@ public boolean equals(Object obj)@b@ {@b@ return this.delegate.equals(obj);@b@ }@b@@b@ public void putAll(Map<? extends K, ? extends V> inMap) {@b@ for (Map.Entry e : inMap.entrySet())@b@ put(e.getKey(), e.getValue());@b@ }@b@@b@ public Collection<V> values()@b@ {@b@ throw new UnsupportedOperationException();@b@ }@b@@b@ public Set<Map.Entry<K, V>> entrySet() {@b@ throw new UnsupportedOperationException();@b@ }@b@@b@ public void addExpirationListener(ExpirationListener<V> listener) {@b@ this.expirationListeners.add(listener);@b@ }@b@@b@ public void removeExpirationListener(ExpirationListener<V> listener)@b@ {@b@ this.expirationListeners.remove(listener);@b@ }@b@@b@ public ExpiringMap<K, V>.Expirer getExpirer() {@b@ return this.expirer;@b@ }@b@@b@ public int getExpirationInterval() {@b@ return this.expirer.getExpirationInterval();@b@ }@b@@b@ public int getTimeToLive() {@b@ return this.expirer.getTimeToLive();@b@ }@b@@b@ public void setExpirationInterval(int expirationInterval) {@b@ this.expirer.setExpirationInterval(expirationInterval);@b@ }@b@@b@ public void setTimeToLive(int timeToLive) {@b@ this.expirer.setTimeToLive(timeToLive);@b@ }@b@@b@ public class Expirer@b@ implements Runnable@b@ {@b@ private final ReadWriteLock stateLock = new ReentrantReadWriteLock();@b@ private long timeToLiveMillis;@b@ private long expirationIntervalMillis;@b@ private boolean running = false;@b@ private final Thread expirerThread;@b@@b@ public Expirer()@b@ {@b@ this.expirerThread = new Thread(this, "ExpiringMapExpirer-" + ExpiringMap.access$008());@b@@b@ this.expirerThread.setDaemon(true);@b@ }@b@@b@ public void run() {@b@ if (this.running) {@b@ processExpires();@b@ try@b@ {@b@ Thread.sleep(this.expirationIntervalMillis);@b@ }@b@ catch (InterruptedException e) {@b@ }@b@ }@b@ }@b@@b@ private void processExpires() {@b@ ExpiringMap.ExpiringObject o;@b@ long timeNow = System.currentTimeMillis();@b@@b@ Iterator i$ = ExpiringMap.access$100(this.this$0).values().iterator();@b@ while (true) { while (true) { if (!(i$.hasNext())) return; o = (ExpiringMap.ExpiringObject)i$.next();@b@@b@ if (this.timeToLiveMillis > 0L)@b@ break;@b@ }@b@@b@ long timeIdle = timeNow - o.getLastAccessTime();@b@@b@ if (timeIdle >= this.timeToLiveMillis) {@b@ ExpiringMap.access$100(this.this$0).remove(o.getKey());@b@@b@ for (ExpirationListener listener : ExpiringMap.access$200(this.this$0))@b@ listener.expired(o.getValue());@b@ }@b@ }@b@ }@b@@b@ public void startExpiring()@b@ {@b@ this.stateLock.writeLock().lock();@b@ try@b@ {@b@ if (!(this.running)) {@b@ this.running = true;@b@ this.expirerThread.start();@b@ }@b@ } finally {@b@ this.stateLock.writeLock().unlock();@b@ }@b@ }@b@@b@ public void startExpiringIfNotStarted()@b@ {@b@ this.stateLock.readLock().lock();@b@ try {@b@ if (this.running)@b@ {@b@ return; } } finally { this.stateLock.readLock().unlock();@b@ }@b@@b@ this.stateLock.writeLock().lock();@b@ try {@b@ if (!(this.running)) {@b@ this.running = true;@b@ this.expirerThread.start();@b@ }@b@ } finally {@b@ this.stateLock.writeLock().unlock();@b@ }@b@ }@b@@b@ public void stopExpiring()@b@ {@b@ this.stateLock.writeLock().lock();@b@ try@b@ {@b@ if (this.running) {@b@ this.running = false;@b@ this.expirerThread.interrupt();@b@ }@b@ } finally {@b@ this.stateLock.writeLock().unlock();@b@ }@b@ }@b@@b@ public boolean isRunning()@b@ {@b@ this.stateLock.readLock().lock();@b@ try@b@ {@b@ boolean bool = this.running;@b@@b@ return bool; } finally { this.stateLock.readLock().unlock();@b@ }@b@ }@b@@b@ public int getTimeToLive()@b@ {@b@ this.stateLock.readLock().lock();@b@ try@b@ {@b@ int i = (int)this.timeToLiveMillis / 1000;@b@@b@ return i; } finally { this.stateLock.readLock().unlock();@b@ }@b@ }@b@@b@ public void setTimeToLive()@b@ {@b@ this.stateLock.writeLock().lock();@b@ try@b@ {@b@ this.timeToLiveMillis = (timeToLive * 1000L);@b@ } finally {@b@ this.stateLock.writeLock().unlock();@b@ }@b@ }@b@@b@ public int getExpirationInterval()@b@ {@b@ this.stateLock.readLock().lock();@b@ try@b@ {@b@ int i = (int)this.expirationIntervalMillis / 1000;@b@@b@ return i; } finally { this.stateLock.readLock().unlock();@b@ }@b@ }@b@@b@ public void setExpirationInterval()@b@ {@b@ this.stateLock.writeLock().lock();@b@ try@b@ {@b@ this.expirationIntervalMillis = (expirationInterval * 1000L);@b@ } finally {@b@ this.stateLock.writeLock().unlock();@b@ }@b@ }@b@ }@b@@b@ private class ExpiringObject@b@ {@b@ private K key;@b@ private V value;@b@ private long lastAccessTime;@b@ private final ReadWriteLock lastAccessTimeLock = new ReentrantReadWriteLock();@b@@b@ ExpiringObject(, V key, long value)@b@ {@b@ if (value == null) {@b@ throw new IllegalArgumentException("An expiring object cannot be null.");@b@ }@b@@b@ this.key = key;@b@ this.value = value;@b@ this.lastAccessTime = lastAccessTime;@b@ }@b@@b@ public long getLastAccessTime() {@b@ this.lastAccessTimeLock.readLock().lock();@b@ try@b@ {@b@ long l = this.lastAccessTime;@b@@b@ return l; } finally { this.lastAccessTimeLock.readLock().unlock();@b@ }@b@ }@b@@b@ public void setLastAccessTime() {@b@ this.lastAccessTimeLock.writeLock().lock();@b@ try@b@ {@b@ this.lastAccessTime = lastAccessTime;@b@ } finally {@b@ this.lastAccessTimeLock.writeLock().unlock();@b@ }@b@ }@b@@b@ public K getKey() {@b@ return this.key;@b@ }@b@@b@ public V getValue() {@b@ return this.value;@b@ }@b@@b@ public boolean equals()@b@ {@b@ return this.value.equals(obj);@b@ }@b@@b@ public int hashCode()@b@ {@b@ return this.value.hashCode();@b@ }@b@ }@b@}