版权声明:本文为博主原创文章,转载请说明出处 https://blog.csdn.net/u010002184/article/details/82145185
import java.util.ArrayList;
import java.util.HashMap;
public class Main {
//ThreadLocal<HashMap> totalMap = new ThreadLocal<HashMap>();//return null; 会造成NullPointerException
ThreadLocal<HashMap> totalMap = new ThreadLocal<HashMap>() {//每个线程下的ThreadLocalMap里有一个Entry的key是totalMap
@Override
protected HashMap initialValue() {
//return super.initialValue();// return null; 会造成NullPointerException
System.out.println(Thread.currentThread().getName() + " totalMap initialValue...");
return new HashMap();
}
};
ThreadLocal<ArrayList> totalList = new ThreadLocal<ArrayList>() {//每个线程下的ThreadLocalMap里有一个Entry的key是totalList
@Override
protected ArrayList<Integer> initialValue() {
System.out.println(Thread.currentThread().getName() + " totalList initialValue...");
return new ArrayList<Integer>();
}
};
public void test() {
Thread[] runs = new Thread[3];
for (int id = 0; id < 2; id++) {
runs[id] = new Thread(new T1(id));//id参数是每个线程的独有标识
runs[id].start();
}
}
class T1 implements Runnable {
int id;
public T1(int id) {
this.id = id;
}
@Override
public void run() {
//
HashMap map = totalMap.get();//这个map是该线程对应的ThreadLocalMap里的一个Entry里的value,totalMap是该Entry的key
System.out.println("totalMap:" + totalMap);
for (int j = 0; j < 5; j++) {
map.put(j, j + id * 100);//每个线程有自己的map,虽然key相同,但是并没有把value覆盖
}
System.out.println("map.hashCode:" + map.hashCode());
System.out.println(Thread.currentThread().getName() + ",map:" + map);
ArrayList<Integer> list = totalList.get();////这个map是该线程对应的ThreadLocalMap里的一个Entry里的value,totalList是该Entry的key
System.out.println("totalList:" + totalList);
for (int j = 0; j < 5; j++) {
list.add(j + id * 100);
}
System.out.println("list.hashCode:" + list.hashCode());
System.out.println(Thread.currentThread().getName() + ",list:" + list);
}
}
public static void main(String[] args) {
Main main = new Main();
main.test();
}
}
输出:
Thread-0 totalMap initialValue...
totalMap:Main$1@77724958
Thread-1 totalMap initialValue...
map.hashCode:0
Thread-0,map:{0=0, 1=1, 2=2, 3=3, 4=4}
totalMap:Main$1@77724958
map.hashCode:508
Thread-1,map:{0=100, 1=101, 2=102, 3=103, 4=104}
Thread-1 totalList initialValue...
totalList:Main$2@7fe8489f
Thread-0 totalList initialValue...
list.hashCode:124091461
totalList:Main$2@7fe8489f
Thread-1,list:[100, 101, 102, 103, 104]
list.hashCode:28660961
Thread-0,list:[0, 1, 2, 3, 4]
总结:
1 每个线程Thread对应一个ThreadLocalMap
2 ThreadLocalMap是由Entry数组组成,元素是键值对,
3 该ThreadLocal<?>变量名是共用的,每个线程的ThreadLocalMap的Entry的key就是该变量名,value就是各自的内容
4 有几个共用的ThreadLocal<?>变量,则每个线程的ThreadLocalMap就有几个Entry,Entry数组初始容量是16,后续可以进行扩容
源码:
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
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();
}
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
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;
}
/**
* Returns the current thread's "initial value" for this
* thread-local variable. This method will be invoked the first
* time a thread accesses the variable with the {@link #get}
* method, unless the thread previously invoked the {@link #set}
* method, in which case the {@code initialValue} method will not
* be invoked for the thread. Normally, this method is invoked at
* most once per thread, but it may be invoked again in case of
* subsequent invocations of {@link #remove} followed by {@link #get}.
*
* <p>This implementation simply returns {@code null}; if the
* programmer desires thread-local variables to have an initial
* value other than {@code null}, {@code ThreadLocal} must be
* subclassed, and this method overridden. Typically, an
* anonymous inner class will be used.
*
* @return the initial value for this thread-local
*/
protected T initialValue() {
return null;
}
initialValue方法的注释:如果编程者期望初始化一个非空的变量,必须要重写这个方法,典型的可以使用匿名内部类。如果不重写该方法会报错。
参考:
https://www.jianshu.com/p/c64f06f0823b Java ThreadLocal 原理分析
http://www.cnblogs.com/digdeep/p/4510875.html ThreadLocal 源码剖析