前言
老样子还是贴源码,更方便。
官方解释:该类提供线程本地变量。 这些变量的不同之处在于,访问这些变量的每个线程都有自己的、独立初始化的变量副本。变量的副本实例通常是私有的静态字段。
甚至他还举了个例子!如下。
// 官方源码
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadId {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId =
new ThreadLocal<Integer>() {
@Override protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadId.get();
}
}
/*
利用官方源码。
官方解释当每个线程使用这个ThreadLocal类变量值时,都会在线程中创建一个副本
所以,当我在下面创建两个线程的时候,A线程中有一个threadId副本。
B线程中也有一个threadId副本。如果在假定A线程比B线程先执行。
那么A中threadId为0,B中threadId为1。且A中能访问B中的副本,因为官方都说了
每个线程都有自己的、独立初始化的变量副本。(在后续中慢慢解释)
*/
public class ThreadLocalTest {
public static void main(String[] args) {
new Thread(ThreadId::get).start();// A线程
new Thread(ThreadId::get).start();// B线程
}
}
整体概述
先看看ThreadLocal整体的结构(从源码中剔除了不需要的),SuppliedThreadLocal内部类我不粘贴,后续会提到。
ThreadLocal中有一个静态内部类ThreadLocalMap,在ThreadLocalMap中维护了一个Entry静态类,还有一个Entry数组名为table的属性。在Entry类中,继承了 WeakReference<ThreadLocal<?>,所以Enrty可以存放ThreadLocal的弱引用。table数组里的每个下标都是根据ThreadLocal中的threadLocalHashCode算出来的,每个线程的threadLocalHashCode都不一样,所以table[i]里存放的该线程里某个ThreadLocal的Entry。
ThreadLocal中的方法都是用来操作ThreadLocalMap对象的。
ThreadLocalMap是用来存储ThreadLocal的弱引用和对应的值
Thread是具体使用的,Thread通过ThreadLocal中的方法操作ThreadLocalMap
// ThreadLocal也是源码,我去掉了大部分的源码,只露了结构
public class ThreadLocal<T> {
private final int threadLocalHashCode = nextHashCode();
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
}
}
ThreadLocal属性:
private final int threadLocalHashCode = nextHashCode();
1、线程标识,不同的线程该值不同;2、在ThreadLocalMap中确定线程的位置;值不同,在ThreadLocalMap中位置不同,线程就能对自己的副本安全访问,避免了与其他线程的冲突。
private static AtomicInteger nextHashCode = new AtomicInteger();
修饰符时static,是类变量。这个是用来返回线程的threadLocalHashCode值的。
private static final int HASH_INCREMENT = 0x61c88647;
修饰符时static,是类变量。这个是has增加量。解释一下为什么是这个值,这个值是斐波那契数列,它在二进制表示下可以产生较好的散列分布特性。主要还是避免和其他线程拥有同样的threadLocalHashCode值
ThreadLocal方法
private static int nextHashCode()
/*
计算下一个线程的threadLocalHashCode
这是属性的定义private final int threadLocalHashCode = nextHashCode();
调用的就是该方法
*/
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
protected T initialValue()
/*
在最开始没有set方法,直接调用get方法时,最后就会调用该方法;
get方法返回的就是该值。
*/
protected T initialValue() {
return null;
}
public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier)
java8出现的该方法,为啥?因为Supplier接口函数也是java8出现的。
创建SuppliedThreadLocal对象时,调用Supplier对象的get方法来获取初始值,并将其设置为线程局部变量的值。每个ThreadLocal都只有一个SuppliedThreadLocal对象。
/**
* Creates a thread local variable. The initial value of the variable is
* determined by invoking the {@code get} method on the {@code Supplier}.
*
* @param <S> the type of the thread local's value
* @param supplier the supplier to be used to determine the initial value
* @return a new thread local variable
* @throws NullPointerException if the specified supplier is null
* @since 1.8
*/
public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
return new SuppliedThreadLocal<>(supplier);
}
public ThreadLocal()
public ThreadLocal() {
}
public T get()
/*
1、获取ThreadLocalMap存放的值
ThreadLocalMap.Entry中存放的key是当前的ThreadLocal副本实例,value是对应值
2、获取SuppliedThreadLocal值(该值调用setInitialValue方法获取)
*/
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();
}
private T setInitialValue()
/*
调用get方法时,如果从ThreadLocalMap中获取不到值,则调用该方法。
该方法中的initialValue方法,SuppliedThreadLocal类重写了,所以
1.如果该类是SuppliedThreadLocal则调用SuppliedThreadLocal中的对应方法,
返回之前提到的的withInitial方法中的值。
2.如果该类是ThreadLocal,ThreadLocal的initialValue返回null。
后面的Thread.currentThread();,就是给当前线程的ThreadLocalMap设置值。
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
public void set(T value)
/*
调用ThreadLocal中的set为当前线程的ThreadLocalMap设置值。
getMap()方法获取该线程的ThreadLocalMap
map.set方法是当ThreadLocalMap不为null时,
表明已经创建了线程已经有ThreadLocalMap,
所以直接调用ThreadLocalMap进行设置值。set方法后续详细说
如果不存在ThreadLocalMap ,则需要调用createMap创建一个ThreadLocalMap
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public void remove()
/*
Thread.remove是用来在ThreadLocalMap中移除线程的当前ThreadLocal。
*/
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
ThreadLocalMap getMap(Thread t)
/*
获取线程的ThreadLocalMap
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue)
/*
创建ThreadLocalMap并当前ThreadLocal弱引用做key放入到ThreadLocalMap
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap)
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
T childValue(T parentValue) {
throw new UnsupportedOperationException();
}
内部类SuppliedThreadLocal
特殊的一个获取值方法,该类是静态修饰的,且继承了ThreadLocal类,重写了initialValue方法。
调用了构造方法参数(Supplier参数)。在ThreadLocal中通过public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier)方法构造一个SuppliedThreadLocal类。并在get方法中,通过initialValue调用该方法。
static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {
private final Supplier<? extends T> supplier;
SuppliedThreadLocal(Supplier<? extends T> supplier) {
this.supplier = Objects.requireNonNull(supplier);
}
@Override
protected T initialValue() {
return supplier.get();
}
}
内部类ThreadLocalMap
该类的所有属性和方法都是私有的,Thread线程只能通过ThreadLocal方法间接调用里面的方法。
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
/**
* The initial capacity -- MUST be a power of two.
*/
private static final int INITIAL_CAPACITY = 16;
/**
* The table, resized as necessary.
* table.length MUST always be a power of two.
*/
private Entry[] table;
/**
* The number of entries in the table.
*/
private int size = 0;
/**
* The next size value at which to resize.
*/
private