zoukankan      html  css  js  c++  java
  • java中ThreadLocal入门

    前言

    ThreadLocal可以看做线程的本地变量,实现原理就是每个线程保存一份数据的副本,数据隔离,以空间换时间。

    简单使用

    public class Client3 {
    
      public static void main(String[] args) {
        ThreadLocal<String> nameThreadLocal = new ThreadLocal<>() {
          @Override
          protected String initialValue() {
            return "test";
          }
        };
    
        for (int i = 1; i <= 5; i++) {
          int finalI = i;
          new Thread(() -> {
            String name = "lisi" + finalI;
            nameThreadLocal.set(name);
            System.out.println(Thread.currentThread() + " set name " + name);
            try {
              Thread.sleep((long) (Math.random() * 1000));
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
            System.out.println(Thread.currentThread() + " get name " + nameThreadLocal.get());
          }, "thread" + finalI).start();
        }
      }
    
    }
    

    输出为

    Thread[thread3,5,main] set name lisi3
    Thread[thread5,5,main] set name lisi5
    Thread[thread2,5,main] set name lisi2
    Thread[thread1,5,main] set name lisi1
    Thread[thread4,5,main] set name lisi4
    Thread[thread4,5,main] get name lisi4
    Thread[thread5,5,main] get name lisi5
    Thread[thread1,5,main] get name lisi1
    Thread[thread2,5,main] get name lisi2
    Thread[thread3,5,main] get name lisi3
    

    每个线程向TheadLocal中设置值和取值,数据都是互不影响的。如果没设置值,取initialValue()方法的初始值。

    原理分析

    /**
         * Sets the current thread's copy of this thread-local variable
         * to the specified value.  Most subclasses will have no need to
         * override this method, relying solely on the {@link #initialValue}
         * method to set the values of thread-locals.
         *
         * @param value the value to be stored in the current thread's copy of
         *        this thread-local.
         */
        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;
        }
    
    /* ThreadLocal values pertaining to this thread. This map is maintained
         * by the ThreadLocal class. */
        ThreadLocal.ThreadLocalMap threadLocals = null;
    

    获取当前线程的threadLocals,类型为ThreadLocalMap,可以简单看做一个HashMap,key为ThreadLocal对象(实际上是它的弱引用),value为要设置的值。

    /**
             * The entries in this hash map extend WeakReference, using
             * its main ref field as the key (which is always a
             * ThreadLocal object).  Note that null keys (i.e. entry.get()
             * == null) mean that the key is no longer referenced, so the
             * entry can be expunged from table.  Such entries are referred to
             * as "stale entries" in the code that follows.
             */
            static class Entry extends WeakReference<ThreadLocal<?>> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }
    

    弱引用如果没有关联的强引用,活不过下一次GC,使用弱引用是为了方便垃圾清理。

    /**
             * Set the value associated with key.
             *
             * @param key the thread local object
             * @param value the value to be set
             */
            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();
            }
    
    /**
             * Increment i modulo len.
             */
            private static int nextIndex(int i, int len) {
                return ((i + 1 < len) ? i + 1 : 0);
            }
    

    ThreadLocalMap使用线性探测法解决哈希冲突。

    参考

    ThreadLocal源码解读

  • 相关阅读:
    17.Letter Combinations of a Phone Number(递归生成序列)
    BZOJ 4052 Magical GCD
    管理学的入门经典书籍,初级管理学书籍推荐
    关于经营战略的书,商业战略书籍推荐
    如何成为一名合格的销售管理者?
    能帮你提升沟通能力的书籍推荐
    提升领导力心得体会
    口才和说服力的书籍推荐,学会说服别人你需要看这本书
    团队管理的书籍推荐 ,这些书教你如何打造团队
    管理学必读书单推荐:这些书教你学好经营管理知识
  • 原文地址:https://www.cnblogs.com/strongmore/p/14968708.html
Copyright © 2011-2022 走看看