- 軽量
- スレッドセーフ
それだけです。 このタスクをjava.util.concurrentで書く前は対処していませんでした。 このパッケージを使用するというアイデアは、同僚の1人によって促されました。同僚は似たようなものを持っていましたが、必要な機能とは一致しませんでした。 それでは、始めましょう:
キーは内部クラスになり、その直接的な目的に加えて、その存在が終了したため、「ライブ」であるか、キャッシュから削除できるかを決定します。
private static class Key { private final Object key; private final long timelife; public Key(Object key, long timeout) { this.key = key; this.timelife = System.currentTimeMillis() + timeout; } public Key(Object key) { this.key = key; } public Object getKey() { return key; } public boolean isLive(long currentTimeMillis) { return currentTimeMillis < timelife; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Key other = (Key) obj; if (this.key != other.key && (this.key == null || !this.key.equals(other.key))) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 43 * hash + (this.key != null ? this.key.hashCode() : 0); return hash; } @Override public String toString() { return "Key{" + "key=" + key + '}'; } }
キャッシュクラス自体がパラメーター化されます。 内部にはストレージコンテナが必要です。 java.util.concurrent.ConcurrentHashMapが最適に機能します。 デフォルトのストレージ時間は、別のフィールドによってリースされます。 次に、java.util.concurrent.ScheduledExecutorServiceを作成します。
public class CacheUtil<K, V> { private ConcurrentHashMap<Key, V> globalMap = new ConcurrentHashMap<Key, V>(); private long default_timeout; private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread th = new Thread(r); th.setDaemon(true); return th; } }); }
メインスレッドが終了すると、キャッシュをクリアするプロセスも終了するように、スレッドを悪魔にします。
コンストラクターでシェダーを実行します。シェダーは、一定の時間(この場合、オブジェクトの保存時間の5番目の部分です)マップを調べて、有効期限が切れたオブジェクトをすべて削除します。
public CacheUtil(long default_timeout) throws Exception { if (default_timeout < 100) { throw new Exception("Too short interval for storage in the cache. Interval should be more than 10 ms"); } default_timeout = default_timeout; scheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { long current = System.currentTimeMillis(); for (Key k : globalMap.keySet()) { if (!k.isLive(current)) { globalMap.remove(k); } } } }, 1, default_timeout/5, TimeUnit.MILLISECONDS); }
次に、キャッシュを操作するメソッドを追加します-これですべてが使用可能になります。 完全なコードは次のとおりです。
public class Cahe<K, V> { private volatile ConcurrentHashMap<Key, V> globalMap = new ConcurrentHashMap<Key, V>(); private long default_timeout; private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread th = new Thread(r); th.setDaemon(true); return th; } }); /** * @param default_timeout - . */ public Cache(long default_timeout) throws Exception { if (default_timeout < 10) { throw new Exception("Too short interval for storage in the cache. Interval should be more than 10 ms"); } this.default_timeout = default_timeout; scheduler.scheduleAtFixedRate(new Runnable() { @Override public void run() { long current = System.currentTimeMillis(); for (Key k : globalMap.keySet()) { if (!k.isLive(current)) { globalMap.remove(k); } } } }, 1, default_timeout/5, TimeUnit.MILLISECONDS); } /** * @param default_timeout - */ public void setDefault_timeout(long default_timeout) throws Exception { if (default_timeout < 100) { throw new Exception("Too short interval for storage in the cache. Interval should be more than 10 ms"); } this.default_timeout = default_timeout; } /** * * * @param <K> * @param <V> * @param key * @param data */ public void put(K key, V data) { globalMap.put(new Key(key, default_timeout), data); } /** * * @param <K> * @param <V> * @param key * @param data * @param timeout */ public void put(K key, V data, long timeout) { globalMap.put(new Key(key, timeout), data); } /** * * @param <K> * @param <V> * @param key * @return */ public V get(K key) { return globalMap.get(new Key(key)); } /** * * @param <K> * @param key - */ public void remove(K key) { globalMap.remove(new Key(key)); } /** * */ public void removeAll() { globalMap.clear(); } /** * . * . * @param <K> * @param <V> * @param map */ public void setAll(Map<K, V> map) { ConcurrentHashMap tempmap = new ConcurrentHashMap<Key, V>(); for (Entry<K, V> entry : map.entrySet()) { tempmap.put(new Key(entry.getKey(), default_timeout), entry.getValue()); } globalMap = tempmap; } /** * * . * @param <K> * @param <V> * @param map */ public void addAll(Map<K, V> map) { for (Entry<K, V> entry : map.entrySet()) { put(entry.getKey(), entry.getValue()); } } private static class Key { private final Object key; private final long timelife; public Key(Object key, long timeout) { this.key = key; this.timelife = System.currentTimeMillis() + timeout; } public Key(Object key) { this.key = key; } public Object getKey() { return key; } public boolean isLive(long currentTimeMillis) { return currentTimeMillis < timelife; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Key other = (Key) obj; if (this.key != other.key && (this.key == null || !this.key.equals(other.key))) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 43 * hash + (this.key != null ? this.key.hashCode() : 0); return hash; } @Override public String toString() { return "Key{" + "key=" + key + '}'; } } }