【JAVA Reference】ReferenceQueue 与 Reference 源码剖析(二)

我的原则:先会用再说,内部慢慢来。
学以致用,根据场景学源码


一、架构

1.1 代码架构图

在这里插入图片描述

1.2 状态流程图
1.2.1 简易流程图

在这里插入图片描述
在这里插入图片描述

1.2.2 UML流程图 (单ReferenceQueue)

在这里插入图片描述

1.2.3 UML流程图 (多ReferenceQueue)

在这里插入图片描述

1.2.4 Reference对象的状态通过成员变量next和queue来判断
状态 Next Queue discovered
Active null referenceQueue 下一个要回收的 reference(gc决定)(假如是最后一个,那么就是 this )
Pending this referenceQueue 下一个要进入队列的 reference (假如是最后一个,那么就是 this )
Enqueued 队列中下一个节点(假如是最后一个,next = this) ReferenceQueue.ENQUEUED null
Inactive this ReferenceQueue.NULL null

在 Active 与 Pending 状态下的, discovered 就相当于 next。

1.2.5 未注册 ReferenceQueue

如果未注册 Queue,那么就只有 Active 与 Inactive 状态。
在这里插入图片描述

=== 点击查看top目录 ===

二、ReferenceQueue 源码剖析

ReferenceQueue队列是一个单向链表,ReferenceQueue里面只有一个head 成员变量持有队列的队头。后进先出的队列,其实是个就是个栈!!!

2.1 ReferenceQueue 类

ReferenceQueue和 Reference 类都是 jdk1.2 的时候出的,所以也就不可能继承jdk1.5出来的Queue接口

package java.lang.ref;
import java.util.function.Consumer;
public class ReferenceQueue<T> {
     
     

    public ReferenceQueue() {
     
      }

    private static class Null<S> extends ReferenceQueue<S> {
     
     
        boolean enqueue(Reference<? extends S> r) {
     
     
            return false;  //内部类,它是用来做状态识别的,重写了enqueue入队方法,永远返回false,所以它不会存储任何数据,见后面的NULL和ENQUEUED两个标识成员变量
        }
    }

    /*
    	状态State:Inactive
    	1. 当 Reference对象创建时没有指定 queue,设置为 NULL
    	2. 该 Reference 被拉出队列的时候,设置为 NULL
	*/ 
    static ReferenceQueue<Object> NULL = new Null<>();

    /*
    	状态State:ENQUEUED
    	Reference已经被ReferenceHander线程从pending队列移到queue里面时。设置为 ENQUEUED
    	所以ENQUEUED状态不可能在调用 enqueue 方法
    */
    static ReferenceQueue<Object> ENQUEUED = new Null<>();

    static private class Lock {
     
      };
    // 锁对象,只是用来这个类加锁用
    private Lock lock = new Lock();

    // 头节点(有存放数据)
    private volatile Reference<? extends T> head = null;
    // 队列真实长度
    private long queueLength = 0;
	// 如果Reference创建时没有指定队列或Reference对象已经在队列里面了,则直接返回
    boolean enqueue(Reference<? extends T> r) {
     
      }

    private Reference<? extends T> reallyPoll() {
     
     }
    public Reference<? extends T> poll() {
     
     
        if (head == null)
            return null;
        synchronized (lock) {
     
     
            return reallyPoll();
        }
    }
 	//将头部第一个对象移出队列并返回,如果队列为空,则等待timeout时间后,返回null,这个方法会阻塞线程
    public Reference<? extends T> remove(long timeout){
     
     }
    //将队列头部第一个对象从队列中移除出来,如果队列为空则直接返回null(此方法不会被阻塞)
    public Reference<? extends T> remove(){
     
     return remove(0);}
    void forEach(Consumer<? super Reference<? extends T>> action) {
     
     }
}
2.1.1 Null 内部类
  • java.lang.ref.ReferenceQueue.Null
  • 内部类,它是用来做状态识别的,重写了enqueue入队方法,永远返回false,所以它不会存储任何数据,见后面的NULL和ENQUEUED两个标识成员变量
private static class Null<S> extends ReferenceQueue<S> {
     
     
        boolean enqueue(Reference<? extends S> r) {
     
     
            return false; 
        }
    }

=== 点击查看top目录 ===

2.2 enqueue 方法
   boolean enqueue(Reference<? extends T> r) {
     
     
        synchronized (lock) {
     
     
            // Check that since getting the lock this reference hasn't already been
            // enqueued (and even then removed)
            ReferenceQueue<?> queue = r.queue;
            // 如果Reference创建时没有指定队列或Reference对象已经在队列里面了,则直接返回
            if ((queue == NULL) || (queue == ENQUEUED)) {
     
     
                return false;
            }
            assert queue == this;   //!!! 只有r的队列是当前队列才允许入队
            r.queue = ENQUEUED; //将r的queue设置为ENQUEUED状态,标识Reference已经入队
            r.next = (head == null) ? r : head;  // 往头部插 ,类似于栈结构</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值