给每个线程拷贝一个线程自己本地的变量副本,每个线程就直接操作自己的本地副本就ok了,然后就跟其他的线程就没有冲突了,避免多个线程并发的访问同一个共享的数据。重点就是用一个变量,同时多个线程操作的时候不让变量是共享。

源码剖析

设置值流程

  1. public void set(T value) {
  2. Thread t = Thread.currentThread();
  3. ThreadLocalMap map = getMap(t);
  4. if (map != null)
  5. map.set(this, value);
  6. else
  7. createMap(t, value);
  8. }
  1. Thread t = Thread.currentThread();获取当前线程
  2. ThreadLocalMap map = getMap(t);获取Thread的ThreadLocalMap,这个map只能是自己线程内部可以使用。一个Thread可以放多个ThreadLocal

image.png

  1. map != null;如果map不为空就可以直接set,没有map就得创建

    1. map.set(this, value); key就是当前线程的ThreadLocal对象,value就是设置的值

      1. private void set(ThreadLocal<?> key, Object value) {
      2. // We don't use a fast path as with get() because it is at
      3. // least as common to use set() to create new entries as
      4. // it is to replace existing ones, in which case, a fast
      5. // path would fail more often than not.
      6. Entry[] tab = table;
      7. int len = tab.length;
      8. int i = key.threadLocalHashCode & (len-1);
      9. for (Entry e = tab[i];
      10. e != null;
      11. e = tab[i = nextIndex(i, len)]) {
      12. ThreadLocal<?> k = e.get();
      13. if (k == key) {
      14. e.value = value;
      15. return;
      16. }
      17. if (k == null) {
      18. replaceStaleEntry(key, value, i);
      19. return;
      20. }
      21. }
      22. tab[i] = new Entry(key, value);
      23. int sz = ++size;
      24. if (!cleanSomeSlots(i, sz) && sz >= threshold)
      25. rehash();
      26. }

      获取值流程

      1. public T get() {
      2. Thread t = Thread.currentThread();
      3. ThreadLocalMap map = getMap(t);
      4. if (map != null) {
      5. ThreadLocalMap.Entry e = map.getEntry(this);
      6. if (e != null) {
      7. @SuppressWarnings("unchecked")
      8. T result = (T)e.value;
      9. return result;
      10. }
      11. }
      12. return setInitialValue();
      13. }
  2. Thread t = Thread.currentThread();获取当前线程

  3. ThreadLocalMap map = getMap(t);拿到线程的ThreadLocalMap
  4. ThreadLocalMap.Entry e = map.getEntry(this); 通过当前线程的ThreadLocal对象找到那个entry数组
  5. T result = (T)e.value;从entry数组中获取值,然后返回。