1. 程式人生 > >Java高並發程序設計(九)--ThreadLocal

Java高並發程序設計(九)--ThreadLocal

好習慣 可能 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() {return
in;} 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