软引用类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会在引发“内存不足”异常前先回收这些对象的内存。软引用可用来实现内存敏感的高速缓存。
Java自带了一个 WeakHashMap 类用以实现弱引用,自带一个 SoftCache 类用以实现软引用缓存,以下给出自定义的软引用类的源码。
package com.ffcs.ods.common.util; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import java.util.Set; /** * @版权:福富软件 版权所有 (c) * @文件:com.ffcs.ods.common.util.SoftHashMap.java * @author: g.yanjj * @see: Map, HashMap, WeakHashMap, SoftCache * @创建日期: * @功能说明:具有软引用特性的哈希表,可用于存放缓存数据 * @修改记录: */ public class SoftHashMap<K,V> implements Map<K,V> { /** * 用来存放软引用的内部Map */ private final Map<K, SoftReferValue<K,V>> hash = new HashMap<K, SoftReferValue<K,V>>(); /** * 用来存放已被清除的软引用对象 */ private ReferenceQueue<V> queue = new ReferenceQueue<V>(); /** * 需要保留最近使用的缓存的数量,为0则代表不用特意保留缓存 */ private final int HARD_SIZE; /** * 用来保留最近使用的缓存的FIFO链表,将最近使用过的缓存存入链首 */ private final LinkedList<V> hardCache = new LinkedList<V>(); /** * 具有软引用特性的哈希表 */ public SoftHashMap() { HARD_SIZE = 0; } /** * 具有软引用特性的哈希表 * * @param keepSize 指定最多需要保留的最近使用过的缓存数量 */ public SoftHashMap(int keepSize) { HARD_SIZE = keepSize; } /** * 清除所有的键值对,执行后哈希表为空。 */ @Override public void clear() { hardCache.clear(); clearReferQueue(); hash.clear(); } /** * 判断哈希表是否包含指定的键 * * @param key 要判断的键对象,键对象为null时一定返回false。 * @return <tt>true</tt> 包含指定键,<tt>false</tt> 不包含指定键。 */ @Override public boolean containsKey(Object key) { if (null != key){ clearReferQueue(); return hash.containsKey(key); } else { return false; } } /** * 判断哈希表是否包含有指定的值 * * @param value 要判断的值对象,值对象为null时一定返回false。 * @return <tt>true</tt> 包含指定值,<tt>false</tt> 不包含指定值。 */ @Override public boolean containsValue(Object value) { if (null != value) { clearReferQueue(); for (SoftReferValue<K,V> srv : hash.values()) { if (value.equals(srv.get())) { return true; } } } return false; } /** * SoftHashMap类并没有使用内部集,因此此方法会抛出一个异常 * * @return 不会返回任何对象,抛出异常 * @exception UnsupportedOperationException */ @Override public Set<Map.Entry<K,V>> entrySet() { //没有内部集合类 throw new UnsupportedOperationException(); } /** * 根据键对象,获取值对象。 * * <p>由于值对象可能会被回收,此方法只会返回键存在,并且未被回收的值对象。 * * <p>如果在构造函数中指定了“缓存保留数”,则最近获取的“缓存保留数”个数的值对象将不会被回收。 * * @param key 要用于取值的键对象 * @return 返回对应的未被回收的值对象,如果键不存在或值对象已被回收,则返回{@code null} */ @Override public V get(Object key) { V result = null; //根据键获取值的引用 SoftReferValue<K,V> valueRef = hash.get(key); if (null != valueRef) { //软引用所指向的对象有可能已被回收,因此需要判断目标对象是否为空 result = valueRef.get(); if (null == result) { //如果目标对象已被回收,则从哈希表中移除这个无效键值对 hash.remove(key); clearReferQueue(); } else { //如果需要保留最近使用的缓存,则将目标对象推入强引用链表 if (HARD_SIZE > 0) { hardCache.addFirst(result); if (hardCache.size() > HARD_SIZE) { hardCache.removeLast(); } } } } return result; } /** * 判断哈希表是否是空的 * * @return <tt>true</tt>哈希表没有任何键值对,<tt>false</tt>哈希表至少有一个键值对。 */ @Override public boolean isEmpty() { return size() == 0; } /** * 返回哈希表的键对象的集合 */ @Override public Set<K> keySet() { return hash.keySet(); } /** * 将键值对添加到哈希表 * * @param key 键对象类似一个索引,可用于查找值对象 * @param value 值对象是保存实际数据的对象,可通过键对象查找 * @return 如果该键对象之前已在哈希表中存在,则返回原有的值对象。 * 如果返回{@code null},可能是该键对象第一次添加到哈希表,或原先存放的值对象为null,或原先存放的值对象已被回收。 */ @Override public V put(K key, V value) { clearReferQueue(); SoftReferValue<K,V> srv = new SoftReferValue<K,V>(value, key, queue); srv = hash.put(key, srv); if (null == srv){ return null; } else { return srv.get(); } } /** * 将指定Map中的键值对,批量添加到哈希表 * * @param m 要添加到哈希表的源表 */ @Override public void putAll(Map<? extends K, ? extends V> m) { for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { Map.Entry<? extends K, ? extends V> e = i.next(); hash.put(e.getKey(), new SoftReferValue<K,V>(e.getValue(), e.getKey(), queue)); } } /** * 根据指定键,从哈希表移除对应的键值对 * * @param key 要移除的键 * @return 返回被移除的值对象,如果哈希表不存在指定键则返回{@code null} */ @Override public V remove(Object key) { clearReferQueue(); SoftReferValue<K,V> srv = hash.remove(key); if (null == srv){ return null; } else { return srv.get(); } } /** * 返回哈希表有效的键值对数量,在返回之前,已被回收的值对象将被移除 * * @return 哈希表有效的键值对数量 */ @Override public int size() { clearReferQueue(); return hash.size(); } /** * SoftHashMap类不支持返回值对象集合,此方法会抛出一个异常 * * @return 不会返回任何对象,抛出异常 * @exception UnsupportedOperationException */ @Override public Collection<V> values() { //不支持获取软引用集合 throw new UnsupportedOperationException(); } /** * 继承的软引用内部类,加入key属性是为了方便从值对象查找对应的键 */ private static class SoftReferValue<K,V> extends SoftReference<V> { private final K key; private SoftReferValue(V value, K key, ReferenceQueue<V> queue) { super(value, queue); this.key = key; } } /** * 清空引用队列,清除已被回收的软引用对象 */ private void clearReferQueue() { SoftReferValue<K,V> srv; while ((srv = (SoftReferValue<K,V>) queue.poll()) != null) { hash.remove(srv.key); } } }
相关推荐
ArrayList 是一个数组实现的列表,LinkedList 是一个链表实现的列表,HashSet 是一个基于哈希表的集合。 3. synchronized 关键字 synchronized 关键字用于实现线程同步,它可以将一个方法或代码块锁定,使其只能被...
- 应用场景:用于实现弱哈希表等。 - 特点:垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。 **3.4 虚引用(Phantom Reference)** ...
强引用、软引用、弱引用、虚引用,分别对应不同的垃圾回收策略,适用于内存管理的不同场景。 8. **hashCode的作用**: hashCode()方法返回对象的哈希值,常用于哈希表(如HashMap)的快速查找。不同的对象应具有...
- HashMap与HashSet的内部实现:理解哈希表和红黑树的原理。 6. **多线程** - 线程的创建:通过Thread类和Runnable接口创建线程。 - 线程状态:理解新建、就绪、运行、阻塞和死亡五种状态。 - 同步机制:...
- **软引用**:当内存不足时,垃圾收集器会回收软引用的对象。 - **弱引用**:垃圾收集器在任何时候都可以回收弱引用对象。 - **虚引用**(幻象引用):仅用于跟踪对象被垃圾收集的状态,无法通过虚引用来访问...
根据《Java语言规范》,Java中有四种不同类型的引用:强引用(Strong References)、软引用(Soft References)、弱引用(Weak References)和虚引用(Phantom References)。 - 强引用是最常用的引用类型,只要强...
- **SoftReference**(软引用):当系统即将发生内存溢出时,会被回收。 - **WeakReference**(弱引用):在下一次垃圾回收时就会被回收。 - **FinalReference**(强引用):最常用的引用类型,只要还有强引用指向一...
- **软引用**:当内存不足时可能被回收。 - **弱引用**:在下一次GC时一定会被回收。 - **虚引用**:主要用于跟踪对象的销毁过程。 #### JUC/并发相关知识点 - **ThreadLocal原理**:每个线程拥有独立的副本,避免...
- **HashMap原理**:基于哈希表实现,提供高效的数据查找。 - **HashMap为什么不直接使用hashCode()处理后的哈希值直接作为table的下标**:为了减少哈希冲突。 - **HashMap、HashTable、ConcurrentHashMap**:...
13. **Java的四种引用**:强引用、软引用、弱引用和虚引用,控制对象的生命周期,用于内存管理和避免内存泄漏。 14. **泛型**:泛型提供了类型安全,允许在编译时检查类型。 15. **创建对象方式**:new关键字、...
- **软引用**:当 JVM 认为有必要回收内存之前,即使内存不足也不会被回收。 - **弱引用**:更弱一些的引用类型,在下一次垃圾回收时会被回收。 - **虚引用**:无法通过虚引用来获取对象实例,主要用来跟踪对象被...
弱引用、软引用和虚引用对象在特定条件下也会被回收。 4. **重写equals()与hashCode()**:在重写`equals()`方法时,通常需要同时重写`hashCode()`方法,以保持`equals()`比较相等的对象具有相同的哈希码,以满足`...
- **软引用**:用于描述有用但不是必须的对象,仅当系统即将发生内存溢出异常时,才会被回收。 - **弱引用**:比软引用更弱一些,只要发生垃圾收集,不管内存是否充足,都会被回收。 - **虚引用**:也称为幽灵引用或...
- 软引用:在内存不足时,软引用的对象会被回收。常用于缓存,以便在内存紧张时释放资源。 - 弱引用:即使内存充足,只要对象只有弱引用,就会被回收,适合短期缓存。 - 虚引用:最弱的引用,无法直接访问对象,...
4. **内存管理**:垃圾收集机制,对象的生命周期,引用类型(强、软、弱、虚引用)。 5. **IO流**:字节流和字符流,缓冲流,对象序列化。 6. **反射机制**:动态加载类,获取类信息,调用方法,创建对象。 以上...
- 内存管理:垃圾回收机制、引用类型(强引用、软引用、弱引用、虚引用)。 - 多线程:线程的创建方式、同步机制(synchronized关键字、Lock接口)。 - 文件与IO流:文件操作、字节流和字符流。 - 泛型:类型参数、...
合理设置缓存策略,例如使用软引用或弱引用,可以防止内存溢出,同时减少对数据库的频繁访问。 2. **第二级缓存配置** 第二级缓存可以跨Session共享数据,使用像Ehcache这样的缓存提供者可以显著提升性能。但需要...
- 引用类型:强引用、软引用、弱引用和虚引用,影响垃圾回收的行为。 5. **集合框架** - `List`, `Set`, `Queue`: 提供各种数据结构,如数组列表(ArrayList)、链表(LinkedList)、哈希集(HashSet)等。 - `...
- 同样基于哈希表实现,但更加线程安全。 ### 三、并发编程 1. **ThreadLocal的底层原理** - `ThreadLocal` 通过每个线程拥有独立的变量副本实现线程间的隔离。 - 主要用于解决线程安全问题。 2. **如何理解...
- 使用哈希表来快速查找进程。 - **4.5.2 双向循环链表** - 维护进程之间的链接关系。 - **4.5.3 运行队列** - 存放就绪态的进程。 - **4.5.4 等待队列** - 等待特定条件满足的进程集合。 **4.6 内核线程** - ...