public class TestThreadLocal extends Thread{
//1.在线程的run方法外 new ThreadLocal对象
ThreadLocal<ThreadLocal> threadLocal = new ThreadLocal();
@Override
public void run(){
if ("Thread-1".equals(Thread.currentThread().getName()))
{
//如果是线程1,就等待100ms完成,再执行.保证先执行0,再执行1
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" 前 "+threadLocal.get());
threadLocal.set(threadLocal);
System.out.println(Thread.currentThread().getName()+" 后 "+threadLocal.get());
}
public static void main(String[] args) {
TestThreadLocal t1 = new TestThreadLocal();
TestThreadLocal t2 = new TestThreadLocal();
t1.start();
t2.start();
try {
sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果
Thread-0 前 null
Thread-0 后 java.lang.ThreadLocal@3554f93f
Thread-1 前 null
Thread-1 后 java.lang.ThreadLocal@b8bf527
简单分析:
Thread-0先执行,往ThreadLoacl里存入对象,但当Thread-1去存之前去拿时,还是空。验证了ThradLocal线程安全,隔离。
ThreadLocal的set 和 get 方法
set方法
threadLocal.set(threadLocal);
//ThreadLocal.set(T value)
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); //getMap(t)方法
if (map != null) {
map.set(this, value); //正常map的set方法,键为当前threadLocal对象
} else {
createMap(t, value); //2.1 节 createMap
}
}
先获取当前线程,然后获取ThreadLocalMap对象,将值set入map中,map的**key为ThreadLocal对象,value为传入的值**。
-
getMap
(t)ThreadLocalMap map = getMap(t);
//ThreadLocal.getMap(Thread t)
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
返回当前线程的threadLocals对象。
// Thread类中threadLocals对象
ThreadLocal.ThreadLocalMap threadLocals = null;
createMap
(t, value);
//ThreadLocal.createMap(Thread t, T firstValue)
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
createMap方法即创建ThreadLocalMap对象,并存入值。
ThreadLocalMap
是ThreadLocal的 静态内部类
//ThreadLocal里的静态内部类ThreadLocalMap
static class ThreadLocalMap {
/**
* 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 int threshold; // Default to 0
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private void set(ThreadLocal<?> key, Object value) {...}
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
}
get方法
threadLocal.get()
;
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); //2.2节 getMap
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
map.getEntry(this);
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
总结
每个Thread中都具备一个ThreadLocalMap,每个ThreadLocalMap可以存储多个【key=ThreadLocal,value=自设置】的map键值对。
调用threadlocal.set()方法,即是传入当前threadlocal对象去当前thread类中去找map【thread类中的threadlocalmap引用】,找到map后将其键值对存入map【key=threadlocal对象,value=set方法参数】。
调用threadlocal.get()方法,即是传入当前threadlocal对象去当前thread类中去找map拿值。该map中可以还储存其他key=threadlocal2 的键值对。
ThreadLocal本身并不存储值,它只是在线程的ThreadLocalMap变量中作为一个key来让线程从ThreadLocalMap获取value,每个value都是与ThreadLocal对象关联在一起的。
中途发现了一个好玩的事情,关于join()方法
t.join() 的作用是 谁执行t.join()方法就等待t执行完毕(t是一个线程实体)
如果是 Thread.currentThread().join(); 呢?
结果是:线程一直在阻塞,无法终止。自己等待自己结束,这也是个坑呀。