ThreadLocal

ThreadLocal

  • ThreadLocal
    • 用法
    • 底层结构
      • ThreadLocal的hash
      • 内存泄漏
      • 过期删除处理

ThreadLocal

在多线程情况下,在线程类中使用ThreadLocal可以为每个线程配置私有的对象

    ThreadLocal<Object> threadLocal = new ThreadLocal<>();

用法

他们使用 get()和 set() 方法来获取默认值或将其值更改为当前线程所存的副本的值,从而避免了线程安全问题

底层结构

这个类中只有一个ThreadLocal对象,但是每一个线程中都有不同的ThreadLocalMap

最终的变量是放在了当前线程的ThreadLocalMap中,并将ThreadLocal这个对象的弱引用作为键

	//ThreadLocal的set方法可以说明一切
    public void set(T value) {
    	//这个t代表当前线程
        Thread t = Thread.currentThread();
        //ThreadLocalMap是ThreadLocal的内部类,这让每个线程都有一个map
        ThreadLocalMap map = getMap(t);
        //map没有得到,创建一个当前线程的map
        //有map则向map中存值
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }

ThreadLocal的hash

ThreadLocalMap类似hashmap,但是所使用的hash函数、碰撞处理等方法大不相同

碰撞处理使用动态寻址法

ThreadLocalMap中存储的是entry,这个是ThreadLocalMap的内部类,它是一个ThreadLocal类型的弱引用,在map中充当键的位置

在ThreadLocalMap.set()方法的最后,如果执行完启发式清理工作后,未清理到任何数据,且当前散列数组中Entry的数量已经达到了列表的扩容阈值(len*2/3),就开始执行rehash()逻辑,也就是扩容处理

内存泄漏

让一个虚引用当值主要是为了防止内存泄漏,当ThreadLocal需要被回收的时候,如果在map中的键是强引用,那么这个对象是无法被回收掉的

        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

ThreadLocal需要我们解决的的内存泄漏问题是下面这种

因为ThreadLocalMap的键为弱引用,值为强引用,每次GC后,键的指向都为null(因为ThreadLoacl被回收掉了,但是这个弱引用指针并没有被回收),值的指向对象依然没有被回收,产生了OOM问题

解决办法是在使用完毕后调用remove方法手动清除

过期删除处理

当Map中的键指向null的时候代表这个数据过期了,需要被回收掉,ThreadLocal提供了俩种过期删除策略

1,探测式清理操作
2,启发式清理

你可能感兴趣的:(分布式,jvm,java,开发语言)