Java高并发程序设计(九)--ThreadLocal

如果说锁是让线程有序的争夺资源的话,那么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()方法。

 

posted @ 2018-08-07 15:35  蒋曾  阅读(195)  评论(0编辑  收藏  举报