ThreadLocal 类解析
什么是ThreadLocal
JDK里面关于ThreadLocal的解释就是:它提供一个线程局部变量,很拗口对不对,没错就是这么拗口,所以你用的少,我们都用的少。它其实就是说,在一个类里面,这个类可以被很多线程访问,那么ThreadeLocal给这些线程,每一个分配一个他们自己私有的局部变量。还是拗口对不对?不着急,现在只要知道,它就是给多线程环境下,每个线程分配一个单独的变量。
ThreadLocal 的组成
我们用idea看看ThreadLocal里面含有什么东西:
初一看貌似挺多的。其实在这个里面它主要实现了一个Map,如果你还记得它是为每个线程分配一个独立的变量,那么也就不难理解,它其实就是往map里面给每个线程设置了一个变量给他们使用。
然后看看ThreadLocal,主要就是几个方法:get(),set(T),initialValue(),remove(),其中initialValue是protected:
1 | protected T initialValue() { |
它主要是提醒所有的继承者,它需要初始化值。
然后看看get():
1 | public T get() { |
从这里就可以看到一个事情:get的时候它用到了Thread.currentThread(),然后又用getMap(threade)。为啥会这样?它貌似使用的thread做的键,对么?也就是当前线程。没错,一个map里面它用当前线程做key,然后取到当前线程的value,而不会影响到其它的线程。顺便看下ThreadLocalMap类,看到它是一个static class ThreadLocalMap {},这是不是就是静态变量唯一了?
其它的set(),remove()就不多说了,肯定也是操作这个map。
ThreadLocal 使用
讲了一些简单的源码,貌似也没弄明白到底怎么用它,使用它又有什么效果?我们接下来看下实例,我们使用一个序列号生成器来看下实际效果。
首先我们定义一个序列号接口,主要用来获取序列号Sequence.java:
1 | /** |
然后我们写一个生成序列号任务类ClientThread.java:
1 | /** |
现在在客户端A我们开启三个任务,首先不用ThreadLocal:
1 | /** |
控制台结果为:
可以看到每个线程对于number都是直接加的,这和static变量有关,但是我们如果想要每个线程都有单独的属性number了?只对我当前线程可以用,别人都不可以用了?
我们加上ThreadLocal看看:
1 |
|
在看下结果:
可以看到number的值在每个线程里面都是单独私有的,线程0不会影响线程1的number值。没错,这就是ThreadLocal了。