ThreadLocal特性及使用场景:
1、方便同一个线程使用某一对象,避免不必要的参数传递;
2、线程间数据隔离(每个线程在自己线程里使用自己的局部变量,各线程间的ThreadLocal对象互不影响);
3、获取数据库连接、Session、关联ID(比如日志的uniqueID,方便串起多个日志);
ThreadLocal应注意:
1、ThreadLocal并未解决多线程访问共享对象的问题;
2、ThreadLocal并不是每个线程拷贝一个对象,而是直接new(新建)一个;
3、如果ThreadLocal.set()的对象是多线程共享的,那么还是涉及并发问题。
1、ThreadLocal<T>初始化
private
final int threadLocalHashCode =
nextHashCode();
private static final int
HASH_INCREMENT=
0x61c88647;
/**
* The next hash code to be given out. Updated atomically.
Starts at zero.
*/
// 源码说nextHashCode初始值为0,但实际调试时显示初始值为1253254570,费解?
// 而且当初始化完毕后,nextHashCode的值又变为0,说明其初始值确实是0的。
private static AtomicInteger nextHashCode = new AtomicInteger();
private static intnextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
ThreadLocal类变量有3个,其中2个是静态变量(包括一个常量),实际作为作为ThreadLocal实例的变量只有threadLocalHashCode这1个,而且已经初始化就不可变了。
创建ThreadLocal实例时有哪些操作呢:
ThreadLocal初始化时会调用nextHashCode()方法初始化threadLocalHashCode,且threadLocalHashCode
初始化后不可变。
threadLocalHashCode可用来标记不同的ThreadLocal实例。
2、内部类
2.1 ThreadLocalMap
ThreadLocalMap是
定制的hashMap,仅用于维护当前线程的本地变量值。仅ThreadLocal类对其有操作权限,是Thread的私有属性。为避免占用空间较大或生命周期较长的数据常驻于内存引发一系列问题,hash table的key是弱引用WeakReferences。当空间不足时,会清理未被引用的entry。
ThreadLocalMap中的重点:
static class Entryextends WeakReference<ThreadLocal<?>>{
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v){
super(k);
value= v;
}
}
Note:
ThreadLocalMap的key是ThreadLocal,value是Object(即我们所谓的“线程本地数据”)。
2.2 SuppliedThreadLocal<T> extends ThreadLocal<T>
SuppliedThreadLocal是JDK8新增的内部类,只是扩展了ThreadLocal的初始化值的方法而已,允许使用JDK8新增的Lambda表达式赋值。需要注意的是,函数式接口Supplier不允许为null。
源码如下:
static final class SuppliedThreadLocal<T>extends ThreadLocal<T>{
private final Supplier<?extends T> suppli