基于软引用实现的缓存, 当内存不够使会自动释放缓存内容, 以避免OOM
软引用(SoftReference)与弱引用(WeakReference) 软引用:如果一个对象只具有软引用, 而当前虚拟机堆内存空间足够, 那么垃圾回收器就不会回收它, 反之就会回收这些软引用指向的对象
弱引用:垃圾回收器一旦发现某块内存上只有弱引用(一定请注意只有弱引用, 没强引用), 不管当前内存空间是否足够, 那么都会回收这块内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 import org.slf4j.Logger;import java.lang.ref.ReferenceQueue;import java.lang.ref.SoftReference;import java.util.HashMap;import java.util.Map;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock; public class SoftReferenceCache <K , V > { private static final Logger log = org.slf4j.LoggerFactory.getLogger("c.SoftReferenceCache" ); private Map<K, InnerSoftReference<V>> cache; private ReferenceQueue<V> queue; private ReadWriteLock lock; public SoftReferenceCache () { cache = new HashMap<K, InnerSoftReference<V>>(); queue = new ReferenceQueue<V>(); lock = new ReentrantReadWriteLock(false ); } public void put (K key, V value) { try { lock.writeLock().lock(); clearInvalidReference(); cache.put(key, new InnerSoftReference<V>(key, value, queue)); } finally { lock.writeLock().unlock(); } } public V get (K key) { try { lock.readLock().lock(); InnerSoftReference<V> softReference = cache.get(key); V v = null ; if (softReference != null ) v = softReference.get(); return v; } finally { lock.readLock().unlock(); } } private void clearInvalidReference () { InnerSoftReference<V> softReference; while ((softReference = (InnerSoftReference) queue.poll()) != null ) { if (softReference.get() == null ) cache.remove(softReference.getKey()); } } public int size () { try { lock.readLock().lock(); int size = cache.size(); log.info(Thread.currentThread().getName() + " 缓存池中对象的个数: " + size); return size; } finally { lock.readLock().unlock(); } } public void clearCache () { try { lock.writeLock().lock(); cache = new HashMap<K, InnerSoftReference<V>>(); queue = new ReferenceQueue<V>(); log.info(Thread.currentThread().getName() + "清空缓存池!" ); } finally { lock.writeLock().unlock(); } } private class InnerSoftReference <V > extends SoftReference <V > { private K key; private InnerSoftReference (K key, V value, ReferenceQueue<V> queue) { super (value, queue); this .key = key; } public K getKey () { return key; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 import org.slf4j.Logger; import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; public class TestSoftReferenceCache { private static final Logger log = org.slf4j.LoggerFactory.getLogger("c.TestSoftReferenceCache" ); private static int MAX_COUNT = 1000 ; private static String KEY_PREFIX = "KEY_" ; private static SoftReferenceCache<String, byte []> cache = new SoftReferenceCache<String, byte []>(); public static void main (String[] args) { ExecutorService es = Executors.newCachedThreadPool(); es.submit(new Customer()); es.submit(new Customer()); es.submit(new Customer()); es.submit(new Customer()); es.submit(new Customer()); es.shutdown(); } static class Customer implements Runnable { @Override public void run () { for (int i = 0 ; i < MAX_COUNT; i++) { byte [] a = cache.get(KEY_PREFIX + i); if (a == null ) { a = new byte [1024 ]; cache.put(KEY_PREFIX + i, a); log.info( Thread.currentThread().getName() + " 向缓存池中添加对象[" + (KEY_PREFIX + i) + "]: " + a); } else { log.info( Thread.currentThread().getName() + " 从缓存池中获取对象[" + (KEY_PREFIX + i) + "]: " + a); } } for (int i = 0 ; i < MAX_COUNT; i++) { byte [] a = cache.get(KEY_PREFIX + i); if (a == null ) { a = new byte [1024 ]; cache.put(KEY_PREFIX + i, a); log.info( Thread.currentThread().getName() + " 向缓存池中添加对象[" + (KEY_PREFIX + i) + "]: " + a); } else { log.info( Thread.currentThread().getName() + " 从缓存池中获取对象[" + (KEY_PREFIX + i) + "]: " + a); } } } } }