ThreadLocal 原理
ThreadLocal之set()
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*/
public void set(T value) {
//获取这个线程对象
Thread t = Thread.currentThread();
//查询线程key对应的值ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);//创建
}
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();
}
ThreadLocal 之ThreadLocalMap
//ThreadLocal.java
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
//Thread.java
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
从上面代码不难发现,每个进程都会拥有一个 “ThreadLocal.ThreadLocalMap threadLocals”而这个map 里面又是ThreadLocal-Object的键值对
不同线程使用同一value的话线程是不安全的
测试方案,创建两个线程value用同一个Test 对象,一个进行加,一个进行减 ,同样循环10000次,发现结果每次不同,且不是0.
Test test = new Test();
Thread one = new Thread("one") {
@Override
public void run() {
super.run();
ThreadLocal<Test> local = new ThreadLocal<Test>();
local.set(test);
for (int i = 0; i < COUNT; i++) {
local.get().add();//进行加
}
System.out.println(local.get().getSum() + Thread.currentThread().getName());
}
};
Thread two = new Thread("two") {
@Override
public void run() {
super.run();
ThreadLocal<Test> local = new ThreadLocal<Test>();
local.set(test);
for (int i = 0; i < COUNT; i++) {
local.get().del();//进行减
}
System.out.println(local.get().getSum() + Thread.currentThread().getName());
}
};
控制太输出
6609one
539two
所以ThreadLocal 只能启到保存变量的作用,不是线程安全