ThreadLocal

所谓ThreadLocal,就是每个线程人手一只笔,线程本地存储。
1、使用
ThreadLocal的常规用法是get和set方法,比如可能这样用

static  ThreadLocal<Object> tlObj = new ThreadLocal<>();
            //如下使用方法
            if(tlObj .get() == null){
                 tlObj .set(new Object());
            }

ThreadLocal的使用时在应用层面(即代码层面)自己来实现相关的控制。

2、原理
Thread有个内部有个ThreadLocalMap的变量,是一个用来存储本线程的ThreadLocal值的Map。

//Thread.java
    ThreadLocal.ThreadLocalMap threadLocals = null;

下面来看下,我们代码中的get和set方法如何实现。
get方法,实现如下。

//ThreadLocal.java
public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

其中,getMap方法如下,即返回线程的threadLocals变量

//ThreadLocal.java
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

get方法的核心就是在当前Thread的threadLocals中寻找以当前ThreadLocal对象为Key存储的T。

再来看看set方法:

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

完全跟get相反的操作,即在当前线程变量Thread的threadLocals中以当前ThreadLocal对象为key存储ThreadLocal的泛型T。

3、再深入一点
Thread对象中的threadLocals是一个ThreadLocalMap,它的每一个Entry结构如下

static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;

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

这是一个弱引用,所谓弱引用,即不影响java虚拟机进行垃圾回收的引用。如果ThreadLocal的强引用被回收后,ThreadLocalMap的key就会变为null,这样系统在ThreadLocalMap清理时,会将这些垃圾数据回收(执行时机不确定)。在线程退出时,会做如下操作。

//Thread.java
private void exit() {
//省略
    threadLocals = null;
//省略
}

将threadLocals置空,会加速threadLocals的回收。
另外,如果需要父子线程进行数据的传递,还有一种做法是使用InheritableThreadLocal。
在线程创建时,会将父线程的该部分进行浅拷贝(即引用赋值),所以注意,如果子线程直接修改了引用,父线程是感知不到的,如果是修改了引用的对象内部的值,父线程还是能感知到的。

//Thread.java
//这东西其实就是InheritableThreadLocal的Map,专门用来实现父子线程之间的传递
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; 

//线程初始化时做了如下动作
private void init(
//此处省略一群变量
if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
            //继承它老爹的家产,浅拷贝
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

就酱,继承遗产这货,还是不再展开了,还有GC也不细讲,都以后展开。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值