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源码解读

  • 相关阅读:
    Code Forces Gym 100886J Sockets(二分)
    CSU 1092 Barricade
    CodeChef Mahesh and his lost array
    CodeChef Gcd Queries
    CodeChef GCD2
    CodeChef Sereja and LCM(矩阵快速幂)
    CodeChef Sereja and GCD
    CodeChef Little Elephant and Balance
    CodeChef Count Substrings
    hdu 4001 To Miss Our Children Time( sort + DP )
  • 原文地址:https://www.cnblogs.com/strongmore/p/14968708.html
Copyright © 2011-2022 走看看