ThreadLocal之四种应用类型

在jdk1.2之前关于对象的引用其实只有一个定义:若reference类型的数据存储着另外一块内存的初始地址,那么这块内存就代表着一个引用。对应的有关引用的状态就是引用和被引用。其实在后来语言的发展过程中,发现对于一些缓存类型的对象若是内存够用则存在,若是不够则清除。那么如何描述这种类型的对象呢?于是便出现了多种类型的引用类型。
1、java你知道的引用类型?
强引用:a = new A();只要引用关系存在永远不会被gc
软引用:SoftReference sr = new SoftReference<>(new T()); 这样创建的对象在堆内存不够的时候,进行垃圾回收的时候会被清除掉。
弱引用:WeakReference wr = new WeakReference<>(new T());这样创建的对象在每一次gc时候都会被回收掉。
虚引用:PhantomReference pr = new PhantomReference<>(new T(),Queue) 唯一作用是在对象被回收之后会受到一个系统通知。jdk中直接内存的回收就用到虚引用,由于jvm自动内存管理的范围是堆内存,而直接内存是在堆内存之外(其实是内存映射文件,自行去理解虚拟内存空间的相关概念),所以直接内存的分配和回收都是有Unsafe类去操作,java在申请一块直接内存之后,会在堆内存分配一个对象保存这个堆外内存的引用,这个对象被垃圾收集器管理,一旦这个对象被回收,相应的用户线程会收到通知并对直接内存进行清理工作。
3、ThreadLocal为什么容易发生内存泄漏,怎么避免?
threadlocal是如何做到将变量作为线程变量呢?其实在tl.set(value)时,并不是将变量放在ThreadLocal中,而是通过获取当前线程,再获取当前线程的ThreadLocalMap 来设置,key为 ThreadLocal tl,value为 T value。本质上还是通过一个Entry设置。 由于 tl是 通过弱应用放在Entry中的,所以在gc时可以及时收走ThreadLocal类型的对象,而收集之后Entry中的key值自然为null,那么value此时是不是就是一直使用的内存了呢?无法被回收?其实这正是replaceStaleEntry存在的意义、将为null值得entry及时利用,防止内存泄漏。

   public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }


        /**
         * Set the value associated with key.
         *
         * @param key the thread local object
         * @param value the value to be set
         */
        private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
  
    


  /**
     * The entries in this hash map extend WeakReference, using
     * its main ref field as the key (which is always a
     * ThreadLocal object).  Note that null keys (i.e. entry.get()
     * == null) mean that the key is no longer referenced, so the
     * entry can be expunged from table.  Such entries are referred to
     * as "stale entries" in the code that follows.
     */
    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值