ThreadLocal

ThreadLocal 是干嘛的

简而言之, ThreadLocal 可以帮助你把某个值绑定到线程上
为什么要把某个值绑定到线程上呢?
我们来看个示例

public class Performance {
    private static long beginTimeMillis;

    public static final void begin() {
        beginTimeMillis = System.currentTimeMillis();
    }

    public static final long end() {
        return System.currentTimeMillis() - beginTimeMillis;
    }
}

这段代码, 如果在单线程环境下使用没有问题, 但如果在多线程环境下使用, 是有问题的 !
如下

public static void main(String[] args) {
    Thread t1 = new Thread() {
        @Override
        public void run() {
            Performance.begin();
            // doSomething();
            long time = Performance.end();
            System.out.println("Cost : " + time);
        }
    };
    Thread t2 = new Thread() {
        @Override
        public void run() {
            Performance.begin();
            // doSomething();
            long time = Performance.end();
            System.out.println("Cost : " + time);
        }
    };
    t1.start();
    t2.start();
}

t1 线程有可能看到 t2 线程设置的 currentTimeMillis , 造成统计错误!
如何避免这种错误呢?
我们肯定希望, 在 t1 线程访问 Performance.begin() 的时候, 把 beginTimeMillis 和 t1 线程关联起来,
在 t2 线程访问 Performance.begin() 的时候, 把 beginTimeMillis 和 t2 线程关联起来,
这样, 当 t1 线程访问 Performance.end() 的时候, 我们就能知道 t1 线程的 beginTimeMillis ,
t2 线程访问 Performance.end() 的时候, 我们就能知道 t2 线程的 beginTimeMillis
从而可以计算出正确的结果!
如何把 beginTimeMillis 和线程进行关联呢 ? ThreadLocal !

ThreadLocal 的使用

ThreadLocal 的使用如下

public class Performance {
    static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public static final void begin() {
        long beginTimeMillis = System.currentTimeMillis();
        threadLocal.set(beginTimeMillis);
    }

    public static final long end() {
        return System.currentTimeMillis() - threadLocal.get();
    }
}

这样, 当 t1 线程 调用 Performance.begin() 时, beginTimeMillis 和 t1 关联了起来, t1 调用 Performance.end() 时, 通过 threadLocal.get() 取出了和 t1 关联的 beginTimeMillis, 从而可以计算出正确的结果.

ThreadLocal 原理

ThreadLocal 是怎么让线程和某个值关联起来的呢 ? 我们看下 Thread 类的源码

public class Thread implements Runnable {
    ...
    /* ThreadLocal values pertaining to this thread. 
     * This map is maintained by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ...
}

Thread 类中有一个名叫 threadLocals 的变量, 专门存储和本线程相关的一些值, 这个变量的类型是 ThreadLocalMap , 是一个集合, 我们只要操作这个变量, 就能让某些值和本线程关联起来.
为了便于我们操作 threadLocals 这个变量, JDK 专门提供了 ThrealLocal 这个类,
或者说为了让我们正确的使用 threadLocals 这个变量, JDK 提供了 ThrealLocal 这个类.
ThreadLocal 的使用上面已经说过了, 我们来看看threadLocal.set(beginTimeMillis); 是如何把值和当前线程关联起来的
ThreadLocal 的 set/get 方法伪代码如下

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = t.threadLocals;
    // this 是指 ThreadLocal 对象
    map.set(this, value);
}
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = t.threadLocals;
    ThreadLocalMap.Entry e = map.getEntry(this);
    T result = (T)e.value;
    return result;
}

可以看到, ThreadLocal 先取得访问当前方法的线程, 然后得到与线程相关的 threadLocals 变量. 然后操作 threadLocals 变量, 就把 线程和值关联起来了

转载于:https://my.oschina.net/ironwill/blog/1612455

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值