• ThreadLocal学习


    源码关于类的注释初识

    源码在类的定义之前有一段注释,大体是这个意思:
    ThreadLocal类提供 thread-local variabels(线程局部变量)
    这些变量与普通变量不同,每个线程都可以通过其 get 或 set方法来访问自己的独立初始化的变量副本
    ThreadLocal的实例通常在类中是private static的一个域,这个域维持与线程相关联的某种状态(例如用户ID或事务ID)

    注释中给出了这样一个例子:

    import java.util.concurrent.atomic.AtomicInteger;
    
    public class ThreadId {
         // Atomic integer containing the next thread ID to be assigned
         private static final AtomicInteger nextId = new AtomicInteger(0);
    
         // Thread local variable containing each thread's ID
         private static final ThreadLocal<Integer> threadId =
             new ThreadLocal<Integer>() {
                 @Override protected Integer initialValue() {
                     return nextId.getAndIncrement();
             }
         };
    
         // Returns the current thread's unique ID, assigning it if necessary
         public static int get() {
             return threadId.get();
         }
     }

    ThreadId这个类对于每个线程都生成一个唯一本地标识(线程id值),这个id在第一次被调用后分配,

    并在随后的调用中保持不变

    关键代码

    public class ThreadLocal<T> {
        /**
         * 内部类ThreadLocalMap中使用,相当于HashMap中的hashCode设计
    * ThradLocalMap类设计了一个静态内部类Entry,其构造方法为(ThreadLocal<?> k,Object v)
    * 搜索Entry时,根据k.threadLocalHashCode值做下标寻址计算
    */ private final int threadLocalHashCode = nextHashCode(); /** * The next hash code to be given out. Updated atomically. Starts at zero. */ private static AtomicInteger nextHashCode = new AtomicInteger(); /** * hash增长值,设计为7
    *
    */ private static final int HASH_INCREMENT = 0x61c88647; /** * 获取下一个hash值 */ private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); } /**
    * 设置ThreadLocal初始值,第一次调用get()方法获取初始值的时候将调用此方法
    * 正常情况下,该方法最多只会被一个线程调用一次,但是如果后续调用了remove()方法接着调用get()时,
    * 该方法也会被调用 * 默认返回是null,如果想设置为非null值,在创建ThreadLocal时使用匿名内部类覆盖此方法
    */ protected T initialValue() { return null; } /** * lambda方式初始化,比使用匿名内部类覆盖initialValue()更易理解
    * ThreadLocal<String> local = ThreadLocal.withInitial(()->"hello")
    */ public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) { return new SuppliedThreadLocal<>(supplier); } /** * 构造方法 * @see #withInitial(java.util.function.Supplier) */ public ThreadLocal() { } /*** 核心方法,获取当前线程变量的值 * @return the current thread's value of this thread-local */ 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); } /** * 清除变量值*/ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); } /** * 核心逻辑之一,查看Thread.java源码可以看到
    * Thread类持有一个ThreadLocal.ThreadLocalMap类型的变量threadLocals
    */ ThreadLocalMap getMap(Thread t) { return t.threadLocals; } /** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @param firstValue value for the initial entry of the map */ void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }/**
    * ThreadLocal设计的一个关键部分,是它的一个静态内部类 * ThreadLocalMap的方法,除了构造方法全部是private的,因此没有任何操作会溢出ThreadLocal
    * 这是一个HashMap结构
    * 查看set方法:set(ThreadLocal<?> key,Object value),可以知道这个map以ThreadLocal对象作为key
    * 但是搜索下标,使用的是key.threadLocalHashCode做计算
    */ static class ThreadLocalMap {
    //Entry是ThreadLocalMap的一个静态内部类
    private Entry[] table; ………… } }

     使用场景

    同一个线程内 不同逻辑间需要共享数据(但又无法通过传值来共享数据),或者在同一个线程内为避免重复创建对象 而希望数据重用等情况

    注意

    对一同一个线程的不同ThreadLocal来讲,这些ThreadLocal共享一个table数组,每个ThreadLocal实例在数组中的索引不同

     
  • 相关阅读:
    RedHat 更新CentOS Yum源(转)
    ubuntu 印象笔记
    (转)FFMPEG filter使用实例(实现视频缩放,裁剪,水印等)
    (转)学习ffmpeg官方示例transcoding.c遇到的问题和解决方法
    源码调用ffmpeg库时,需要注意接口为C接口
    codeforces 722D Generating Sets 【优先队列】
    poj2970 The lazy programmer 【优先队列】
    codeblocks17.12 不能启动调试器
    Unity动画知识之二:Animator动画状态机
    关于unity里pbr技术和材质 unity5默认shader和传统的对比
  • 原文地址:https://www.cnblogs.com/yb38156/p/13977014.html
Copyright © 2020-2023  润新知