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()方法。