java集合之4种Reference
来源:互联网 发布:网络异常请重新登录 编辑:程序博客网 时间:2024/05/29 03:47
public abstract class Reference<T> {
public class SoftReference<T> extends Reference<T> {
public class WeakReference<T> extends Reference<T> {
public class PhantomReference<T> extends Reference<T> {
可以用以下表格总结:
级别
什么时候被垃圾回收
用途
生存时间
强引用
从来不会
对象的一般状态
JVM停止运行时终止
软引用
在内存不足时
缓存
内存不足时终止
弱引用
在垃圾回收时
对象缓存
gc运行后终止
虚引用
Unknown
Unknown
Unknown
Reference:
Reference
内部有几个比较重要的属性
// 用于保存对象的引用,GC会根据不同Reference来特别对待private T referent;// 如果需要通知机制,则保存的对对应的队列ReferenceQueue<? super T> queue;/* 这个用于实现一个单向循环链表,用以将保存需要由ReferenceHandler处理的引用 */Reference next;static private class Lock { };// 锁,用于同步pending队列的进队和出队private static Lock lock = new Lock();// 此属性保存一个PENDING的队列,配合上述next一起使用private static Reference pending = null;
内部类ReferenceHandler
ReferenceHandler
作为Reference的静态内部类,用于实现将pending队列里面的Reference
实例依次添加到不同的ReferenceQueue
中(取决于Reference里面的queue)。该pending的元素由GC负责加入。
注:这里对pending队列进行加锁,个人认为是因为GC线程可能和ReferenceHandler所在的线程并发执行,如GC采用CMS并发收集的时候。
如下代码所示
// 此线程在静态块中启动,即一旦使用了Reference,则会启动该线程private static class ReferenceHandler extends Thread { public void run() { for (;;) { Reference r; synchronized (lock) { if (pending != null) { r = pending; Reference rn = r.next; // 从pending中取下一个元素,如果后继为空,则next指向自身 pending = (rn == r) ? null : rn; r.next = r; } else { try { // 没有则等待,后续加入元素会调用lock.notify唤醒 lock.wait(); } catch (InterruptedException x) { } continue; } } // ... ReferenceQueue q = r.queue; // 如果该Reference注册了对应的Queue,则加入到该Queue中 if (q != ReferenceQueue.NULL) q.enqueue(r); } }}
ReferenceQueue属性
// 用于标识没有注册Queuestatic ReferenceQueue NULL = new Null();// 用于标识已经处于对应的Queue中static ReferenceQueue ENQUEUED = new Null();static private class Lock { };/* 互斥锁,用于同步ReferenceHandler的enqueue和用户线程操作的remove和poll出队操作 */private Lock lock = new Lock();// 队列private volatile Reference<? extends T> head = null;// 队列中的元素个数private long queueLength = 0;
ReferenceQueue.enqueue
只会通过Reference里要调用该方法,用于将Reference放入到当前队列中
boolean enqueue(Reference<? extends T> r) { synchronized (r) { // 判断是否已经入队了 if (r.queue == ENQUEUED) return false; synchronized (lock) { r.queue = ENQUEUED; // 单向循环 r.next = (head == null) ? r : head; head = r; queueLength++; if (r instanceof FinalReference) { sun.misc.VM.addFinalRefCount(1); } // 通知当前挂起的线程(调用remove时有可能会挂起) lock.notifyAll(); return true; } }}
应用 - WeakHashMap
WeakHashMap在使用上和HashMap类型,都是Hash + 链表解决冲突,唯一不同点在于前者的Key是使用虚引用来实现的,即当进行垃圾回收的时候,就是被回收掉,此时WeakHashMap会在下次操作的时候,根据被回收掉的Key,从Map里面移除掉。
Entry
当创建Entry的时候,会注册进当前Map属性的queue,当key被回收后,则该Entry会被放入到queue中,每当操作Map的时候,才会将原有的Value清除掉。(由expungeStaleEntries方法来进行,并且没有启动一个单独的线程来处理,没有必要,这样子简化了逻辑以及避免锁的开销)
// 外部WeakHashMap属性private final ReferenceQueue<Object> queue = new ReferenceQueue<>();/* 这里采用了集成WeakReference而不是直接使用,是因为当被回收的时候,具体的Key是不知道的,这里需要往WeakReference额外加入一些属性,以便在被回收后通知时,能够定位到具体的Key/value */private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> { // 这里属性不能加入key,否则会导致存在强引用而不能被视为WeakReference回收掉 V value; int hash; Entry<K,V> next; Entry(Object key, V value, ReferenceQueue<Object> queue, int hash, Entry<K,V> next) { super(key, queue); this.value = value; this.hash = hash; this.next = next; } // ...}
- java集合之4种Reference
- Java功底之Reference
- Java功底之Reference
- Java功底之Reference
- Java之Reference使用讲解
- Java基本功之Reference详解
- Java 中的 Reference (4种引用类型)
- java的4种Reference学习
- Java基础之集合4
- java之集合Collection 详解之4
- Java集合之Set集合
- java集合之集合简介
- Java集合之集合框架
- Java集合之-Map集合
- Java集合之Set集合
- Java集合之List集合
- java学习教程之Reference详解
- Java学习之4种方法遍历Map集合
- MyEclipse使用中常用到的一些快捷键
- java(web)读取resource下的文件
- wanchain区块链连载(一)架构浅析
- XCTestWD 踩坑 source clear
- POJ
- java集合之4种Reference
- 大数据量下高并发同步的讲解(不看,保证你后悔)
- 关于ConcurrentHashMap的优势及使用
- c++之枚举 快速入门及使用
- JS判断对象{}是否为空
- 关于C++ auto不能识别,C++11在DevC++不能支持的问题
- 微信小程序点击事件无效报错Do not have xx handler in current page的问题的解决方法
- JavaScript中某值与undefined字符串比较
- 并发控制中的乐观锁与悲观锁