Java高並發程序設計(九)--ThreadLocal
阿新 • • 發佈:2018-08-07
好習慣 可能 reat super runnable set方法 err 簡單 weak
如果說鎖是讓線程有序的爭奪資源的話,那麽ThreadLocal就是讓每個線程都有一份資源。
打個比方,鎖是讓一百個人爭奪一只筆區寫字,ThreadLocal就是一百個人每人都有一只筆,在輪到他們寫字的時候寫。
寫個簡單的例子:
public class demo implements Runnable{ static ThreadLocal<test> tl=new ThreadLocal<test>(); static class test { private Integer in; public Integer getIn() {returnin;} test(Integer in){this.in=in;} } public static void main(String[] args) { ExecutorService es=Executors.newFixedThreadPool(10); for(int i=0;i<100;i++) { es.submit(new demo()); } } public void run() { tl.set(new test(new Random().nextInt(100)));try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(tl.get().getIn()); } }
Demo裏有一個test內部類,有一百個線程,每個線程都有一個test類存在ThreadLocal那裏,每個線程訪問自己的test,互不影響。
接下來來看ThreadLocal的原理,從set()方法看起:
public void set(T value) { Thread t= Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
首先獲得現在工作的線程,再獲得一個ThreadLocalMap,ThreadLocalMap是它的內部類:
static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal> { Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } }
、、、、、、、、、 }
可以把它看做和HashMap類似的東西,用ThreadLocal作為key,
然後進入getMap()方法:
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
直接獲得線程的threadLocals,進入Thread,
ThreadLocal.ThreadLocalMap threadLocals = null;
可以看到Thread維護了一個ThreadLocal.ThreadLocalMap,回到set方法,現在我們知道getMap()獲得一個有Thread維護的ThreadLocal內部類,現在它為空,進入else,進入createMap():
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
給Thread中的threadLocals賦值,自己本身作為key,需要維護的值作為Value。
看完set方法,接下來看get()方法:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }
很簡潔明了,從map裏面獲得value,沒什麽好說的,想了解更詳細的可以自己看源碼。
另外,因為threadLocals的引用是在Thread裏面,Thread不退出,意味著它會一直存在,而且如果是由線程池維護線程,線程可能不會退出。
所以最好習慣性用完之後,調用remove()方法。
Java高並發程序設計(九)--ThreadLocal