Bạn cần hai bản đồ: bản đồ giữa khóa bộ nhớ cache và các giá trị weak referenced và một trong ánh xạ hướng đối diện giữa các giá trị tham chiếu yếu và các phím. Và bạn cần một reference queue và một chuỗi dọn dẹp.
Tham chiếu yếu có khả năng di chuyển tham chiếu vào hàng đợi khi đối tượng được tham chiếu không thể truy cập được nữa. Hàng đợi này phải được rút ra bởi một luồng dọn dẹp. Và để dọn dẹp, cần phải lấy chìa khóa để tham khảo. Đây là lý do tại sao bản đồ thứ hai là bắt buộc.
Ví dụ sau đây cho thấy cách tạo bộ nhớ cache với bản đồ băm tham chiếu yếu. Khi bạn chạy chương trình bạn sẽ có được kết quả như sau:
$ javac -Xlint:unchecked Cache.java && java Cache
{even: [2, 4, 6], odd: [1, 3, 5]}
{even: [2, 4, 6]}
Dòng đầu tiên cho thấy các nội dung của bộ nhớ cache trước khi tham chiếu đến danh sách lẻ đã bị xóa và dòng thứ hai sau khi tỷ lệ cược đã bị xóa.
Đây là mã:
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Cache<K,V>
{
ReferenceQueue<V> queue = null;
Map<K,WeakReference<V>> values = null;
Map<WeakReference<V>,K> keys = null;
Thread cleanup = null;
Cache()
{
queue = new ReferenceQueue<V>();
keys = Collections.synchronizedMap (new HashMap<WeakReference<V>,K>());
values = Collections.synchronizedMap (new HashMap<K,WeakReference<V>>());
cleanup = new Thread() {
public void run() {
try {
for (;;) {
@SuppressWarnings("unchecked")
WeakReference<V> ref = (WeakReference<V>)queue.remove();
K key = keys.get(ref);
keys.remove(ref);
values.remove(key);
}
}
catch (InterruptedException e) {}
}
};
cleanup.setDaemon (true);
cleanup.start();
}
void stop() {
cleanup.interrupt();
}
V get (K key) {
return values.get(key).get();
}
void put (K key, V value) {
WeakReference<V> ref = new WeakReference<V>(value, queue);
keys.put (ref, key);
values.put (key, ref);
}
public String toString() {
StringBuilder str = new StringBuilder();
str.append ("{");
boolean first = true;
for (Map.Entry<K,WeakReference<V>> entry : values.entrySet()) {
if (first)
first = false;
else
str.append (", ");
str.append (entry.getKey());
str.append (": ");
str.append (entry.getValue().get());
}
str.append ("}");
return str.toString();
}
static void gc (int loop, int delay) throws Exception
{
for (int n = loop; n > 0; n--) {
Thread.sleep(delay);
System.gc(); // <- obstinate donkey
}
}
public static void main (String[] args) throws Exception
{
// Create the cache
Cache<String,List> c = new Cache<String,List>();
// Create some values
List odd = Arrays.asList(new Object[]{1,3,5});
List even = Arrays.asList(new Object[]{2,4,6});
// Save them in the cache
c.put ("odd", odd);
c.put ("even", even);
// Display the cache contents
System.out.println (c);
// Erase one value;
odd = null;
// Force garbage collection
gc (10, 10);
// Display the cache again
System.out.println (c);
// Stop cleanup thread
c.stop();
}
}
Java API là đầy đủ trong những thói quen kỳ lạ. Bạn luôn có thể viết lại WeakHashMap bằng WeakReference. – Pacerier