reference_references - CSDN
精华内容
参与话题
  • Reference详解

    2018-04-23 17:19:47
    1. 概述图片引用自...当Reference对象被GC处理过,说明这个Reference所指向的对象已经被回收过了,那么这个Reference对象也应该做相应的处理;如果该Referenc...

    1.   概述

    图片引用自https://blog.csdn.net/u011801189/article/details/52723868

    根据Reference这个类里面的注释,整个Reference的继承体系跟GC是紧密联系在一起的。当Reference对象被GC处理过,说明这个Reference所指向的对象已经被回收过了,那么这个Reference对象也应该做相应的处理;如果该Reference对象注册了ReferenceQueue,那么它就会被丢到相应的ReferenceQueue中做回收处理。

    从上图注意到,当Reference对象在Reference.pending队列中时,它们是用discovered 这个成员变量来完成队列的连接的;

    这个Reference对象是active的状态,说明这个Reference所指向的对象还没有成为垃圾,还没有被GC过。这个Reference对象还没有进入Reference的世界,它还在GC的监控下呢;当被垃圾回收后,也就是进入Reference的世界后,这个discovered域被复用作链表的连接,此时并不适用next指针,只是把next指向this

    Reference对象真正被放入它所注册的ReferenceQueue里时,next指针才被使用,用来连接队列;此时discovered域被置为null

    2.   Reference适用场景

    . 软引用,一般使用于一些内存敏感性应用,做cache使用。被软引用的对象,在JVM抛出OutOfMemoryError之前,将会被回收掉。它的这个特性使得它做为进程内部的cache最为合适。 

    弱引用,一般用于保存一些跟对象生命周期相同的一些信息,一旦这些对象被垃圾回收,我们就可以对这些对象进行回收。这个是怎么做到的呢?基本上还是由于Reference所提供的功能有关。去看Reference的构造函数你会发现,它会要求传入一个ReferenceQueue,而这个Queue就是为了提供一种机制,这种机制允许程序员在对象被垃圾回收之前被通知到,而做出一些业务逻辑。而这种机制则弥补了JVMfinalizer机制的不足。因为JVMfinalizer机制并不保证finalizer一定会被调用到,这样当我们希望一个对象生命周期结束后它的相关资源也被释放的逻辑就不能够被保证。而且据说(为证实),finalizer是通过JNI实现,通过JVM调用开销也比较大。而JVM通过提供这种Reference机制,从而为程序员提供了处理资源回收的另外一种方法。 

    虚引用,也是可以提供这种对象被垃圾回收时的通知机制。只不过跟上面两个的区别是,PhantomReferenceget方法被实现了一直返回null。这就意味着,当你通过ReferenceQueue拿到PhantomReference的通知时,你是不能再对它做出一个强引用的,你只能更具需要做出自己的cleanup的逻辑。这也说明了PhantomReferencepre-mortem的,也就是说实在真正finalize之前的。如果通过get方法可以获得对象本身,而后又对其建立一个强引用,则在后面的垃圾回收处理时,就会出错。所以干脆这里不让程序员获得对象的引用。而SoftReferenceWeakReference应该就是在JVMfinalize机制之后的。

     

    今天吃饭的时候想到一个问题,就是对于PhantomReference,它的get方法是返回的null的,如果是这样,我通过ReferenceQueue的方式即使能拿到这个PhantomReference,也还是不能对这个对象做实质的资源回收啊。那到底要怎么做才能回收与它的referent想关联的资源呢?

    publicclassLargeObjectFinalizerextendsPhantomReference<Object> {

     

        publicLargeObjectFinalizer(

          Object referent, ReferenceQueue<? super Object> q) {

            super(referent, q);

        }

     

        publicvoidfinalizeResources() {

            // free resources

            System.out.println("clearing ...");

        }

    }

    然后,在利用这个LargeObjectFinalizer关联到我们的referent

    ReferenceQueue<Object>referenceQueue = new ReferenceQueue<>();

    List<LargeObjectFinalizer>references = new ArrayList<>();

    List<Object>largeObjects = new ArrayList<>();

     

    for (int i = 0; i < 10; ++i) {

        Object largeObject = new Object();

        largeObjects.add(largeObject);

        references.add(new LargeObjectFinalizer(largeObject,referenceQueue));

    }

     

    largeObjects= null;

    System.gc();

     

    Reference<?>referenceFromQueue;

    for(PhantomReference<Object> reference : references) {

        System.out.println(reference.isEnqueued());

    }

     

    while((referenceFromQueue = referenceQueue.poll()) != null) {

        ((LargeObjectFinalizer)referenceFromQueue).finalizeResources();

        referenceFromQueue.clear();

    }

    上面的这个例子很简单,但是足够可以说明问题,当垃圾回收工作时,会把我们的LargeObjectFinalizer放到我们提供的referenceQueue上,然后,我们从它上面取下我们的LargeObjectFinalizer,调用资源回收方法finalizeResources

    我觉得这个算是使用PhantomReference做垃圾回收的一个典型例子了。我们并不是直接使用PhantomReference,而是通过扩展它,将我们要关注的对象,比如这里的Object,以及跟该对象相关联的一些资源,关联到我们的LargeObjectFinalizer中,当然这是需要修改它的构造函数,或者通过其它的一些方式关联到这个LargeObjectFinalizer里面的。只有这样,我们才能通过这个ReferenceQueue的机制,达到垃圾回收的目的。

     

    3.     StrongReference、SoftReference,WeakReference、PhantomReference

     强引用  >  软引用  >  弱引用  >  虚引用

    强引用(StrongReference
        强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。

    软引用(SoftReference

        如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。

        软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

    弱引用(WeakReference

        弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

        弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

    虚引用(PhantomReference

        “虚引用顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

        虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

     

    由于引用和内存回收关系紧密。下面,先通过实例对内存回收有个认识;然后,进一步通过引用实例加深对引用的了解。

     

     


    展开全文
  • 对@Reference 、@Resource和@Autowired的简单理解

    万次阅读 多人点赞 2020-04-23 10:31:54
    主要谈一下对这三个注解的简单理解: @Reference 、@Resource和@Autowired

    主要谈一下对这三个注解的简单理解:

    1.@Autowired

    org.springframework.beans.factory.annotation.Autowired

    SpringBoot项目中常用。简单来说就是引入由Spring容器管理的bean。

    2.@Resource

    javax.annotation.Resource

    作用相当于@Autowired,只不过@Autowired是byType自动注入,而@Resource默认byName自动注入。

    3.@Reference

    @Reference是dubbo的注解,也是注入,他一般注入的是分布式的远程服务的对象,需要dubbo配置使用。

     

    简单来说他们的区别:

    @Reference注入的是分布式中的远程服务对象,@Resource和@Autowired注入的是本地spring容器中的对象。

    展开全文
  • 一提到Reference 99.99%的java程序员都懵逼了",为啥改成汉字了呢?吐槽一下,因为CSDN出bug了,如果你用了%做标题,你的文章就别想用它的编辑器修改了,它的js脚本写的不够健壮,报错了;java.lang.ref....

    原来的标题是:"一提到Reference 99.99%的java程序员都懵逼了",为啥改成汉字了呢?吐槽一下,因为CSDN出bug了,如果你用了%做标题,你的文章就别想用它的编辑器修改了,它的js脚本写的不够健壮,报错了;


    java.lang.ref.Reference

    java程序员都知道如果一个对象没有任何引用了,那么这个对象在gc的时候就被回收了,大部分java程序员是基于我们常见的强引用去理解引用的,强引用这种方式虽然简单直接,但是对于一些特殊的java对象,如缓存数据在内存紧张时自动释放掉空间防止oom、直接内存对象回收之前需自动释放掉其占用的堆外内存,当socket对象被回收之前关闭连接,当文件流对象被回收之前自动关闭打开的文件等操作,强引用就无能为力了,为了实现这些特殊需求,java还引入了除了强引以外的引用类型来辅助对象回收操作 或 监控对象的生存周期。

    先来看看引用类型的大家族:

    在java.lang.ref包下除了ReferenceQueue类,Finalizer、FinalReference、PhantomReference、SoftReference、WeakReference都直接或间接继承了Reference类,想想为什么没有强引用StrongReference?



    理解Reference的关键点在于:

    1. 两个队列pending与ReferenceQueue的作用;

    2. Reference对象4种状态的转换;

    3. ReferenceHander线程的处理过程,它是如何将Pending与ReferenceQueue关联起来的;

    4. Pending队列数据来源;

    理解了以上4个问题,才算真不再对Reference懵逼了,下面就带着这四个问题去看下面的内容。

    Reference构造方法

    我们先来看看这些引用类型的父类都给我们提供了什么?

    其内部提供2个构造函数,除了传入referent对象外,区别就是要不要传入一个ReferenceQueue队列

      Reference(Treferent) {

            this(referent,null);

       }

     

       Reference(T referent,ReferenceQueue<?super T>queue){

            this.referent =referent;

            this.queue = (queue==null)? ReferenceQueue.NULL:queue;

        }

    ReferenceQueue队列的作用就是Reference引用的对象被回收时,Reference对象能否进入到pending队列,最终由ReferenceHander线程处理后,Reference就被放到了这个队列里面(Cleaner对象除外,后面有一篇专门讲Cleaner对象源码),然后我们就可以在这个ReferenceQueue里拿到reference,执行我们自己的操作(至于什么操作就看你想怎么用了),所以这个队列起到一个对象被回收时通知的作用;

    如果不带ReferenceQueue的话,要想知道Reference持有的对象是否被回收,就只有不断地轮训reference对象,通过判断里面的get是否为null(phantomReference对象不能这样做,其get始终返回null,因此它只有带queue的构造函数).这两种方法均有相应的使用场景,取决于实际的应用.如weakHashMap中就选择去查询queue的数据,来判定是否有对象将被回收.而ThreadLocalMap,则采用判断get()是否为null来作处理;

    对于带ReferenceQueue参数的构造方法,如果传入的队列为null,那么就会给成员变量queue赋值为ReferenceQueue.NULL队列,这个NULL是ReferenceQueue对象的一个继承了ReferenceQueue的内部类,它重写了入队方法enqueue,这个方法只有一个操作,直接返回 false,也就是这个对列不会存取任何数据,它起到状态标识的作用;


    Reference的重要成员变量

    //在构造方法传入java对象最后就赋值给了referent,也就是它引用到的对象

    private Treferent;        /* Treated specially by GC */

      //pending队列, pending成员变量与后面的discovered对象一起构成了一个pending单向链表,注意这个成员变量是一个静态对象,所以是全局唯一的,pending为链表的头节点,discovered为链表当前Reference节点指向下一个节点的引用,这个队列是由jvm的垃圾回收器构建的,当对象除了被reference引用之外没有其它强引用了,jvm的垃圾回收器就会将指向需要回收的对象的Reference都放入到这个队列里面(好好理解一下这句话,注意是指向要回收的对象的Reference,要回收的对象就是Reference的成员变量refernt持有的对象,是refernt持有的对象要被回收,而不是Reference对象本身),这个队列会由ReferenceHander线程来处理(ReferenceHander线程是jvm的一个内部线程,它也是Reference的一个内部类,它的任务就是将pending队列中要被回收的Reference对象移除出来,如果Reference对象在初始化的时候传入了ReferenceQueue队列,那么就把从pending队列里面移除的Reference放到它自己的ReferenceQueue队列里(为什么是它自己的?pending队列是全局唯一的队列,但是Reference的queue却不是,它是在构造方法里面指定的,前面说过这里Cleaner对象是个特例),如果没有ReferenceQueue队列,那么其关联的对象就不会进入到Pending队列中,会直接被回收掉,除此之外ReferenceHander线程还会做一些其它操作,后面会讲到

     /* List of References waiting to beenqueued.  The collector adds

         * References to this list, while theReference-handler thread removes

         * them. This list is protected by the above lock object. The

         * list uses the discovered field to linkits elements.

         */

        privatestatic Reference<Object>pending =null;

      //与成员变量pending一起组成pending队列,指向链表当前节点的下一个节点

       /* When active:   next element in a discovered reference listmaintained by GC (or this if last)

         *    pending:   next element in thepending list (or null if last)

         *  otherwise:   NULL

         */

    transientprivate Reference<T>discovered/* used by VM */

     

    //ReferenceQueue队列,这就是我们前面提到的起到通知作用的ReferenceQueue,需要注意的是ReferenceQueue并不是一个链表数据结构,它只持有这个链表的表头对象header,这个链表是由Refence对象里面的next成员变量构建起来的,next也就是链表当前节点的下一个节点(只有next的引用,它是单向链表),所以Reference对象本身就是一个链表的节点,这个链表数据来源前面讲pending队列的时候已经提到了,它是由ReferenceHander线程从pending队列中取的数据构建的(需要注意的是,这个对象并不是一个全局的,它是在构造方法里面传入进来的,所以Reference对象需要进入那个队列是我们自己指定的,也有特例,如FinalReference,Cleaner就是一个内部全局唯一的,无法指定,后面有两篇专门讲他们俩的源码),一旦Reference对象放入了队列里面,那么queue就会被设置为ReferenceQueue.ENQUEUED,来标识当前Reference已经进入到队里里面了;

       volatileReferenceQueue<?super T>queue;

     

      //用来与queue成员变量一同组成ReferenceQueue队列,见上面queue的说明;

       /* When active:   NULL

         *     pending:  this

         *   Enqueued:   next reference inqueue (or this if last)

         *   Inactive:   this

         */

       @SuppressWarnings("rawtypes")

       Reference next;

     

     

     

        //lock成员变量是pending队列的全局锁,如果你搜索这个lock变量会发现它只在ReferenceHander线程run方法里面用到了,不要忘了jvm垃圾回收器线程也会操作pending队列,往pending里面添加Reference对象,所以需要加锁;

       /* Object used to synchronize with thegarbage collector.  The collector

         * must acquire this lock at the beginningof each collection cycle.  It is

         * therefore critical that any code holdingthis lock complete as quickly

         * as possible, allocate no new objects,and avoid calling user code.

         */

       staticprivateclass Lock { };

       privatestatic Locklock =new Lock();


    这里一定要理解pending队列,什么样的Reference对象会进入这个队列。

    进入这个队列的Reference对象需要满足两个条件:

    1.    Reference所引用的对象已经不存在其它强引用;

    2.    Reference对象在创建的时候,指定了ReferenceQueue



    Reference状态及其转换

    如果去查看Reference源码,会发现这个类的开头有一段很长的注释,说明了Reference对象的四种状态:

    /* A Reference instance is in one of four possible internal states:
         *
         *     Active: Subject to special treatment by the garbage collector.  Some
         *     time after the collector detects that the reachability of the
         *     referent has changed to the appropriate state, it changes the
         *     instance's state to either Pending or Inactive, depending upon
         *     whether or not the instance was registered with a queue when it was
         *     created.  In the former case it also adds the instance to the
         *     pending-Reference list.  Newly-created instances are Active.
         *
         *     Pending: An element of the pending-Reference list, waiting to be
         *     enqueued by the Reference-handler thread.  Unregistered instances
         *     are never in this state.
         *
         *     Enqueued: An element of the queue with which the instance was
         *     registered when it was created.  When an instance is removed from
         *     its ReferenceQueue, it is made Inactive.  Unregistered instances are
         *     never in this state.
         *
         *     Inactive: Nothing more to do.  Once an instance becomes Inactive its
         *     state will never change again.
         *
         * The state is encoded in the queue and next fields as follows:
         *
         *     Active: queue = ReferenceQueue with which instance is registered, or
         *     ReferenceQueue.NULL if it was not registered with a queue; next =
         *     null.
         *
         *     Pending: queue = ReferenceQueue with which instance is registered;
         *     next = this
         *
         *     Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
         *     in queue, or this if at end of list.
         *
         *     Inactive: queue = ReferenceQueue.NULL; next = this.
         *
         * With this scheme the collector need only examine the next field in order
         * to determine whether a Reference instance requires special treatment: If
         * the next field is null then the instance is active; if it is non-null,
         * then the collector should treat the instance normally.
         *
         * To ensure that a concurrent collector can discover active Reference
         * objects without interfering with application threads that may apply
         * the enqueue() method to those objects, collectors should link
         * discovered objects through the discovered field. The discovered
         * field is also used for linking Reference objects in the pending list.
         */

    如果你没有耐心看完这段注释,请直接往后看:

    1.       Active:活动状态,对象存在强引用状态,还没有被回收;

    2.       Pending:垃圾回收器将没有强引用的Reference对象放入到pending队列中,等待ReferenceHander线程处理(前提是这个Reference对象创建的时候传入了ReferenceQueue,否则的话对象会直接进入Inactive状态);

    3.       Enqueued:ReferenceHander线程将pending队列中的对象取出来放到ReferenceQueue队列里;

    4.       Inactive:处于此状态的Reference对象可以被回收,并且其内部封装的对象也可以被回收掉了,有两个路径可以进入此状态,

    路径一:在创建时没有传入ReferenceQueue的Reference对象,被Reference封装的对象在没有强引用时,指向它的Reference对象会直接进入此状态;

    路径二、此Reference对象经过前面三个状态后,已经由外部从ReferenceQueue中获取到,并且已经处理掉了。

    Reference对象的状态只需要通过成员变量next和queue来判断:

    1.    Active:   next=null

    2.    Pending:  next = this ,queue = ReferenceQueue

    3.    Enqueued:  queue =ReferenceQueue.ENQUEUED

    4.    Inactive:    next = this  ,queue = ReferenceQueue.NULL; 

    以下是Reference对象状态转换图,用word画的,将就着看吧:

    特例还是要拿出来单独说,上面的图不适用描述Cleaner对象,Cleaner对象是没有Enqueue状态的,它经过HandReference处理时执行其clean方法清理,然后就直接进入了inactive状态了;

    下面简单看一下他们的源码实现,如果你理解了上面所有内容,下面的源码理解起来非常简单,我只做简单的注释说明:

    ReferenceHandler线程源码解析

    ReferenceHandler线程是一个拥有最高优先级的守护线程,它是Reference类的一个内部类,在Reference类加载执行cinit的时候被初始化并启动;它的任务就是当pending队列不为空的时候,循环将pending队列里面的头部的Reference移除出来,如果这个对象是个Cleaner实例,那么就直接执行它的clean方法来执行清理工作;否则放入到它自己的ReferenceQueue里面;

    所以这个线程是pending队列与ReferenceQueue的桥梁;


    /* High-priority thread to enqueue pending References*/

       private static class ReferenceHandler extends Thread {

     

           ReferenceHandler(ThreadGroup g, String name) {

               super(g, name);

           }

     

           public void run() {

               for (;;) {

                    //从pending中移除的Reference对象

                   Reference<Object> r;

                   //此处需要加全局锁,因为除了当前线程,gc线程也会操作pending队列

                   synchronized (lock) {

                        //如果pending队列不为空,则将第一个Reference对象取出

                        if (pending != null) {

                            //缓存pending队列头节点

                            r = pending;

                            //将头节点指向discovered,discovered为pending队列中当前节点的下一个节点,这样就把第一个头结点出队了

                            pending = r.discovered;

                            //将当前节点的discovered设置为null;当前节点出队,不需要组成链表了;

                            r.discovered = null;

                        } else {//如果pending队列为空,则等待

                            try {

                                try {

                                    lock.wait();

                                } catch(OutOfMemoryError x) { }

                            } catch(InterruptedException x) { }

                            continue;

                        }

                   }

                   // 如果从pending队列出队的r是一个Cleaner对象,那么直接执行其clean()方法执行清理操作;

                   if (r instanceof Cleaner) {

                        ((Cleaner)r).clean();

                       //注意这里,这里已经不往下执行了,所以Cleaner对象是不会进入到队列里面的,给它设置ReferenceQueue的作用是为了让它能进入Pending队列后被ReferenceHander线程处理;

                        continue;

                    }

                   //将对象放入到它自己的ReferenceQueue队列里

                   ReferenceQueue<Object> q = r.queue;

                   if (q != ReferenceQueue.NULL) q.enqueue(r);

               }

           }

        }

       //以下是ReferenceHander线程初始化并启动的操作

       static {

            ThreadGroup tg =Thread.currentThread().getThreadGroup();

            for (ThreadGroup tgn = tg;

                 tgn != null;

                 tg = tgn, tgn = tg.getParent());

           //线程名称为Reference Handler

            Thread handler = newReferenceHandler(tg, "Reference Handler");

            /* If there were a special system-onlypriority greater than

             * MAX_PRIORITY, it would be used here

             */

           //线程有最高优先级

           handler.setPriority(Thread.MAX_PRIORITY);

            //设置线程为守护线程;

            handler.setDaemon(true);

            handler.start();

    }

    ReferenceQueue源码解析

    ReferenceQueue队列是一个单向链表,ReferenceQueue里面只有一个header成员变量持有队列的队头,Reference对象是从队头做出队入队操作,所以它是一个后进先出的队列

    public class ReferenceQueue<T> {

     

       public ReferenceQueue() { }

        //内部类,它是用来做状态识别的,重写了enqueue入队方法,永远返回false,所以它不会存储任何数据,见后面的NULL和ENQUEUED两个标识成员变量

        private static class Null<S> extendsReferenceQueue<S> {

           boolean enqueue(Reference<? extends S> r) {

               return false;

           }

        }

        //当Reference对象创建时没有指定queue或Reference对象已经处于inactive状态

    staticReferenceQueue<Object> NULL = new Null<>();

    //当Reference已经被ReferenceHander线程从pending队列移到queue里面时

       static ReferenceQueue<Object> ENQUEUED = new Null<>();

     

    staticprivate class Lock { };

    //出队入队时对队列加锁

    privateLock lock = new Lock();

    //队列头

    privatevolatile Reference<? extends T> head = null;

    //队列长度

       private long queueLength = 0;

        //入队操作,ReferenceHander调用此方法将Reference放入到队列里

       boolean enqueue(Reference<? extends T> r) { /* Called only byReference class */

              //加锁操作队列

    synchronized(lock) {

               //如果Reference创建时没有指定队列或Reference对象已经在队列里面了,则直接返回

               ReferenceQueue<?> queue = r.queue;

               if ((queue == NULL) || (queue == ENQUEUED)) {

                   return false;

               }

                    //只有r的队列是当前队列才允许入队

               assert queue == this;

               //将r的queue设置为ENQUEUED状态,标识Reference已经入队

               r.queue = ENQUEUED;

               //从队列头部入队

               r.next = (head == null) ? r : head;

               head = r;

               //队列里面对象数量+1

               queueLength++;

               //如果r是一个FinalReference实例,那么将FinalReference数量也+1

                if (r instanceof FinalReference) {

                   sun.misc.VM.addFinalRefCount(1);

    /**Vm.addFinalRefCount(int n)方法的源码

      publicstatic void addFinalRefCount(int n) {

           // The caller must hold lock to synchronize the update.

     

           finalRefCount += n;

           if (finalRefCount > peakFinalRefCount) {

               peakFinalRefCount = finalRefCount;

           }

    }

    可以通过sun.misc.VM.getFinalRefCount()和sun.misc.VM.getPeakFinalRefCount()来获取FinalReference对象的当前数量和峰值数量

    ***/

               }

                    //唤醒出队操作的等待线程

               lock.notifyAll();

               return true;

           }

        }

        //Reference对象出队操作,将头部第一个对象移出队列,并将队列长度-1

       @SuppressWarnings("unchecked")

       private Reference<? extends T> reallyPoll() {       /* Must hold lock */

           Reference<? extends T> r = head;

           if (r != null) {

               head = (r.next == r) ?

                   null :

                   r.next; // Unchecked due to the next field having a raw type inReference

               r.queue = NULL;

               r.next = r;

               queueLength--;

               if (r instanceof FinalReference) {

                   sun.misc.VM.addFinalRefCount(-1);

               }

               return r;

           }

           return null;

        }

     

    //将队列头部第一个对象从队列中移除出来,如果队列为空则直接返回null(此方法不会被阻塞)

       public Reference<? extends T> poll() {

           if (head == null)

               return null;

           synchronized (lock) {

               return reallyPoll();

           }

        }

     

       //将头部第一个对象移出队列并返回,如果队列为空,则等待timeout时间后,返回null,这个方法会阻塞线程

       public Reference<? extends T> remove(long timeout)

           throws IllegalArgumentException, InterruptedException

        {

           if (timeout < 0) {

               throw new IllegalArgumentException("Negative timeout value");

           }

           synchronized (lock) {

               Reference<? extends T> r = reallyPoll();

               if (r != null) return r;

               for (;;) {

                   lock.wait(timeout);

                   r = reallyPoll();

                   if (r != null) return r;

                    if (timeout != 0) return null;

               }

           }

        }

       public Reference<? extends T> remove() throws InterruptedException{

           return remove(0);

        }

    }



    展开全文
  • 七、引用(reference)详解

    千次阅读 2017-04-16 22:28:45
    如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。引用不等同于对象本身,根据虚拟机种类的不同,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表...

    什么是引用?

    如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。引用不等同于对象本身,根据虚拟机种类的不同,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄其他与此对象相关的位置

    引用的存储位置、长度、结构

    引用存储在java虚拟机栈中栈帧所对应的局部变量表中,局部变量表的容量以变量槽(Variable Slot, 下称Slot)为单位。虚拟机规范中并没有说明它的长度,也没有明确指出这种引用有怎样的结构,但一般每个Slot都应该能存放一个reference
    一般来说,虚拟机实现至少应当通过这个引用做到两点:
    1. 从此引用中直接或间接地查找到对象在java堆中的数据存放的起始地址索引。
    2. 此引用中直接或间接地查找到对象所属数据类型在方法区中的存储的类型信息。

    引用的分类

    Java将引用分为强引用(Strong Reference)软引用(Soft Reference)弱引用(Weak Reference)、**虚引用(Phantom Reference)**4种,这4种引用强度依次逐渐减弱。
    1. 强引用就是指在程序代码之中普遍存在的,类似Object obj = new Object()这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
    2. 软引用是用来描述一些还有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK 1.2之后,提供了SoftReference类来实现软引用。
    3. 弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK 1.2之后,提供了WeakReference类来实现弱引用。
    4. 虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。在JDK 1.2之后,提供了PhantomReference类来实现虚引用。

    展开全文
  • java中的Reference类型

    千次阅读 2020-04-01 15:18:39
    本文简要总结java中的Reference类型。 最近在研读jdk并发框架,其中AQS是重点,由于我打破砂锅问到底的轻微强迫症,google了AQS作者Doug Lea的论文原文[The java.util.concurrent Synchronizer Framework],有...
  • Java基本功之Reference详解

    万次阅读 2017-12-04 14:04:42
    有这样一种说法,如今争锋于IT战场的两大势力,MS一族偏重于底层实现,Java一族偏重于系统架构。说法根据无从考证,但从两大势力各自的社区力量和图书市场已有... Reference Java世界泰山北斗级大作《Thinking In J
  • java学习教程之Reference详解

    万次阅读 2017-01-24 22:06:14
    这是我们经常说的强引用StrongReference,jvm gc时会检测对象是否存在强引用,如果存在由根对象对其有传递的强引用,则不会对其进行回收,即使内存不足抛出OutOfMemoryError。 除了强引用外,Java还引入了...
  • C++引用reference

    2020-10-14 16:36:36
    引用实际上是指针的一个扩展,引用最主要的特点是:它是一个虚拟的变量,不产生新的变量,只是引用其它已存在的变量,它只存在于我们的源码之中,不占有内存。 首先来举一个引用的例子: #include<...
  • Java篇 - 四种引用(Reference)实战

    千次阅读 2019-01-16 18:58:11
    Java的垃圾回收(GC)是虚拟机自动管理的,前面我有篇文章专门讲GC:《JVM篇 - GC给你整明白》 Java内存管理分为内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象。...
  • 谈谈强引用、软引用、弱引用、幻象引用 我们说的不同的引用类型其实都是逻辑上的,而对于虚拟机来说,主要体现的是对象的不同的可达性(reachable) 状态和对垃圾收集(garbage collector)的影响。...
  • vs调试时出现如下错误信息: 这是获取数据库信息时获取不到造成的,将exe.config中的name名修改下 默认为name="Programs.Properties.Settings.ConnectionString" 修改后的exe.config文件为: ...
  • 解决pycharm导入模块提示“unresolved reference
  • pycharm下导入项目,总是提示unresolved reference,查看项目,是包含有相应的模块的, 可以使用如下方式解决:  
  • PyCharm下解决Unresolved Reference问题

    万次阅读 热门讨论 2018-01-31 12:49:25
    在开发过程,特别是clone项目时在PyCharm中经常出现Unresolved Reference问题,对于有强迫症的人来说,简直不可忍受。 1. 进入PyCharm->Preferences->Build,Excution,Deployment->Console->Python Console勾选上Add...
  • 前言 上文中我们讲解了@Service注解的解析原理,了解到Dubbo默认支持两种方式进行解析,一种是通过springboot 自动配置来做的,另外一种是通过DubboComponentScan 注解来解析的,本文继续也是以DubboComponentScan ...
  • docker: invalid reference format

    万次阅读 2018-10-02 22:46:37
    1 docker镜像的名字中不能包含大写字母,改成小写 2 docker run –p 8080:80 –d nginx 符号错误 “-” 其实为"-" docker run -p 8080:80 -d nginx
  • Kotlin Unresolved reference: 解决办法

    万次阅读 热门讨论 2018-01-05 16:58:05
    kotlin Unresolved reference:错误的解决办法
  • 在实际编译代码的过程中,我们经常会遇到"undefined reference to"的问题,简单的可以轻易地解决,但有些却隐藏得很深,需要花费大量的时间去排查。工作中遇到了各色各样类似的问题,按照以下几
  • 应该新建立项目Console Application,选择项目要保存的文件夹 打开项目文件夹中的dev文件,在dev文件中添加你写好的main ,cpp,还有头文件即可  
  • 描述:模块部分,写一个外部模块导入的时候居然提示unresolved reference,如下,程序可以正常运行,但是就是提示包部分红色,看着特别不美观,下面是解决办法 PyCharm版本: 解决: 1.在项目上 单击右键 -&...
1 2 3 4 5 ... 20
收藏数 643,717
精华内容 257,486
关键字:

reference