在这里给大家推荐一篇博客:http://my.oschina.net/lichhao/blog/111362
ThreadLocal大体的代码:
package java.lang; import java.lang.ref.*; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; public class ThreadLocal<T> { private final int threadLocalHashCode = nextHashCode(); protected T initialValue() { return null; } public ThreadLocal() { } public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; } public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); } static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); } private ThreadLocalMap(ThreadLocalMap parentMap) { Entry[] parentTable = parentMap.table; int len = parentTable.length; setThreshold(len); table = new Entry[len]; for (int j = 0; j < len; j++) { Entry e = parentTable[j]; if (e != null) { @SuppressWarnings("unchecked") ThreadLocal<Object> key = (ThreadLocal<Object>) e.get(); if (key != null) { Object value = key.childValue(e.value); Entry c = new Entry(key, value); int h = key.threadLocalHashCode & (len - 1); while (table[h] != null) h = nextIndex(h, len); table[h] = c; size++; } } } } 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); } private void set(ThreadLocal<?> key, Object value) { // We don't use a fast path as with get() because it is at // least as common to use set() to create new entries as // it is to replace existing ones, in which case, a fast // path would fail more often than not. Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); } /** * Remove the entry for key. */ private void remove(ThreadLocal<?> key) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } } } }
重点看这两个方法
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T) e.value; return result; } } return setInitialValue(); } 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 getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
private void set(ThreadLocal<?> key, Object value);
可以看到键值为ThreadLocal对象,value为要在线程间隔离的值的内容。
注意t.threadLocals;在Thread类中,有这样一个属性
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
每个线程都有自己独立的ThreadLocalMap对象。
所以说,每个线程中都有一个独立的threadLocals,这个属性的类型正是ThreadLocalMap,用于保存和当前线程绑定的变量。
解释:
/**
* 对这段代码的理解:
* 假如我创建十个线程,在这十个线程执行过程中,有十个Student实例被创建,
* 并且每个实例只和当前的线程绑定(通过线程的threadLocals属性)
* 在一个线程的生命周期中,访问的Student实例都是同一个实例---通过ThreadLocal绑定的实例。
* 在这十个线程中,对Student实例的访问都是隔离的,互不影响的,因为每个Student实例都是不同的实例,消除了竞争条件,消除了并发访问。
* 如果当前线程想绑定多个变量,那么就是用多个ThreadLocal来进行相应的绑定。。
* ThreadLocal的适用情况:如果多个线程并发访问的对象实例只允许,也只能创建那么一个,那就没有别的办法了,老老实实的使用同步机制来访问吧。。
*/
package threadlocal; import java.util.Random; /** * 对这段代码的理解: * 假如我创建十个线程,在这十个线程执行过程中,有十个Student实例被创建, * 并且每个实例只和当前的线程绑定(通过线程的threadLocals属性) * 在一个线程的生命周期中,访问的Student实例都是同一个实例---通过ThreadLocal绑定的实例。 * 在这十个线程中,对Student实例的访问都是隔离的,互不影响的,因为每个Student实例都是不同的实例,消除了竞争条件,消除了并发访问。 * 如果当前线程想绑定多个变量,那么就是用多个ThreadLocal来进行相应的绑定。。 * ThreadLocal的适用情况:如果多个线程并发访问的对象实例只允许,也只能创建那么一个,那就没有别的办法了,老老实实的使用同步机制来访问吧 */ public class ThreadLocalDemo2 { //创建线程局部变量studentLocal,在后面你会发现用来保存Student对象 private final static ThreadLocal<Student> studentLocal = new ThreadLocal(); //可以定义多个ThreadLocal,绑定多个变量 public static void main(String args[]) { for (int i = 0; i < 2; i++) { final int finalI = i; Thread t = new Thread() { public void run() { //获取当前线程的名字 String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName + " is running!"); //产生一个随机数并打印 Random random = new Random(); int age = random.nextInt(100); System.out.println("thread " + currentThreadName + " set age to:" + age); //在当前线程第一个调用get方法,返回值肯定为null Student student = studentLocal.get(); if (student == null) { student = new Student(); student.setAge(age); student.setName("stu-" + finalI); studentLocal.set(student); //和当前线程绑定一个实例 } System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge() + " stu name:" + student.getName()); Student sss = studentLocal.get();//在当前线程再次访问和当前线程绑定的Student实例,在当前线程第二次调用该方法。。。。 System.out.println("thread " + currentThreadName + " second read age is:" + sss.getAge() + " stu name:" + student.getName()); } }; t.start(); } } }
运行结果:
Thread-1 is running! Thread-0 is running! thread Thread-0 set age to:80 thread Thread-1 set age to:72 thread Thread-0 first read age is:80 stu name:stu-0 thread Thread-1 first read age is:72 stu name:stu-1 thread Thread-0 second read age is:80 stu name:stu-0 thread Thread-1 second read age is:72 stu name:stu-1
=====END=====