ThreadLocal和InheritableThreadLocal深入探究(一)源码分析

ThreadLocal和InheritableThreadLocal深入探究(一)源码分析

ThreadLocal定义

此类提供线程局部变量。这些变量不同于正常的对应项, 因为每个线程访问一个有自己的、独立初始化的变量副本。实例通常是希望将状态与线程关联的类中的私有静态字段 (例如 用户id或事务id)。

官方示例

import java.util.concurrent.atomic.AtomicInteger;
 public class ThreadId {
     // 自动增长ID
     private static final AtomicInteger nextId = new AtomicInteger(0);
     // 本地线程变量存储此ID
     private static final ThreadLocal<Integer> threadId =
         new ThreadLocal<Integer>() {
             @Override protected Integer initialValue() {
                 return nextId.getAndIncrement();
         }
     };

     // 返回当前线程存储的唯一ID,如果存在的话
     public static int get() {
         return threadId.get();
     }
 }
注意:

Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).

ThreadLocal 持有指向每一个线程的一个引用变量,只要线程存活,并且ThreadLocal 实例是可获得的本地线程消亡后ThreadLocal 也会被GC回收,除非还有别的引用存在。

无参构造器
ThreadLocal()
Creates a thread local variable.

方法摘要

Modifier and Type Method and Description
T get()Returns the value in the current thread’s copy of this thread-local variable.
protected T initialValue()Returns the current thread’s “initial value” for this thread-local variable.
void remove()Removes the current thread’s value for this thread-local variable.
void set(T value)Sets the current thread’s copy of this thread-local variable to the specified value.

具体实现

initialValue
返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用 get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。

若该实现只返回 null;如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。
T get()
返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。
void remove()
移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。
void set(T value)
将此线程局部变量的当前线程副本中的值设置为指定值。

InheritableThreadLocal定义

此类提供线程局部变量。这些变量不同于正常的对应项, 因为每个线程访问一个有自己的、独立初始化的变量副本。实例通常是希望将状态与线程关联的类中的私有静态字段 (例如 用户id或事务id)。
注意:

InheritableThreadLocalThreadLocal 的子类,当子线程创建时,该类可以获得当前线程以及子线程变量的值,子线程接收父线程具有其值的所有可继承线程局部变量的初始值。通常情况下, 子线程的值将与父线程的值相同;但是, 通过重写childValue 方法, 可以使子值成为父项的任意函数。

当每个线程属性在变量中维护时, 可继承的线程局部变量优先于普通的线程局部变量 (例如, 用户 id、事务 id) 必须自动传输到创建的任何子线程。

This class extends ThreadLocal to provide inheritance of values from parent thread to child thread: when a child thread is created, the child receives initial values for all inheritable thread-local variables for which the parent has values. Normally the child’s values will be identical to the parent’s; however, the child’s value can be made an arbitrary function of the parent’s by overriding the childValue method in this class.

Inheritable thread-local variables are used in preference to ordinary thread-local variables when the per-thread-attribute being maintained in the variable (e.g., User ID, Transaction ID) must be automatically transmitted to any child threads that are created.

无参构造器
InheritableThreadLocal() 
Creates a thread local variable.
childValue (T parentValue)
此可继承线程局部变量的子值的初始值作为创建子线程时父线程值的函数。
get, initialValue, remove, set
继承父类ThreadLocal的方法
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
继承父类Object的方法

对比ThreadLocal、InheritableThreadLocal

/**
 * @ClassName: ThreadLocalDemo
 * @Description: ThreadLocal、InheritableThreadLocal测试
 * @Author: 尚先生
 * @CreateDate: 2019/2/22 10:31
 * @Version: 1.0
 */
public class ThreadLocalDemo {

    public static void main(String[] args) throws InterruptedException {
        testThreadLocal();
        TimeUnit.SECONDS.sleep(1);
        System.err.println("-------------分割线---------------");
        testInheritableThreadLocal();
    }

    /**
     * 测试testInheritableThreadLocal父子类线程变量取值
     */
    private static void testInheritableThreadLocal() {
        //模拟多线程创建ThreadLocal
        for (int i = 0; i < 3; i++) {
            new Thread("currentThread-InheritableThreadLocal" + i) {
                @Override
                public void run() {
                    System.out.println("当前线程:" + Thread.currentThread().getName() + " ID:" + MyInheritableThreadLocal.get());
                    for (int j = 0; j < 3; j++) {
                        new Thread("subThread-InheritableThreadLocal" + j) {
                            @Override
                            public void run() {
                                System.out.println("子线程:" + Thread.currentThread().getName() + " ID:" + MyInheritableThreadLocal.get());
                            }
                        }.start();
                    }
                }
            }.start();
        }
    }


    /**
     * 测试ThreadLocal父子类线程变量取值
     */
    private static void testThreadLocal() {
        //模拟多线程创建ThreadLocal
        for (int i = 0; i < 3; i++) {
            new Thread("currentThread-ThreadLocal" + i) {
                @Override
                public void run() {
                    System.out.println("当前线程:" + Thread.currentThread().getName() + " ID:" + MyThreadLocal.get());
                    for (int j = 0; j < 3; j++) {
                        new Thread("subThread-ThreadLocal" + j) {
                            @Override
                            public void run() {
                                System.out.println("子线程:" + Thread.currentThread().getName() + " ID:" + MyThreadLocal.get());
                            }
                        }.start();
                    }
                }
            }.start();
        }
    }

    /**
     * 自定义ThreadLocal实现
     */
    static class MyThreadLocal {
        private static final AtomicInteger nextId = new AtomicInteger(0);

        private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() {
            @Override
            protected Integer initialValue() {
                return nextId.getAndIncrement();
            }
        };

        public static int get() {
            return threadId.get();
        }
    }

    /**
     * 自定义InheritableThreadLocal实现
     */
    static class MyInheritableThreadLocal {
        private static final AtomicInteger nextId = new AtomicInteger(0);
        private static final InheritableThreadLocal<Integer> threadId = new InheritableThreadLocal<Integer>() {
            @Override
            protected Integer initialValue() {
                return nextId.getAndIncrement();
            }
        };

        public static int get() {
            return threadId.get();
        }
    }

}

输出结果

当前线程:currentThread-ThreadLocal2 ID:0
当前线程:currentThread-ThreadLocal0 ID:2
当前线程:currentThread-ThreadLocal1 ID:1
子线程:subThread-ThreadLocal0 ID:3
子线程:subThread-ThreadLocal0 ID:4
子线程:subThread-ThreadLocal0 ID:5
子线程:subThread-ThreadLocal1 ID:6
子线程:subThread-ThreadLocal1 ID:7
子线程:subThread-ThreadLocal1 ID:8
子线程:subThread-ThreadLocal2 ID:9
子线程:subThread-ThreadLocal2 ID:10
子线程:subThread-ThreadLocal2 ID:11
-------------分割线---------------
当前线程:currentThread-InheritableThreadLocal1 ID:1
当前线程:currentThread-InheritableThreadLocal2 ID:2
当前线程:currentThread-InheritableThreadLocal0 ID:0
子线程:subThread-InheritableThreadLocal0 ID:2
子线程:subThread-InheritableThreadLocal0 ID:0
子线程:subThread-InheritableThreadLocal1 ID:2
子线程:subThread-InheritableThreadLocal0 ID:1
子线程:subThread-InheritableThreadLocal1 ID:1
子线程:subThread-InheritableThreadLocal2 ID:0
子线程:subThread-InheritableThreadLocal2 ID:2
子线程:subThread-InheritableThreadLocal2 ID:1
子线程:subThread-InheritableThreadLocal1 ID:0

结果

ThreadLocal里的值,子线程里不能获得;InheritableThreadLocal里的值,子线程可以获得。

相关文章推荐

ThreadLocal深入理解与内存泄漏分析
https://blog.csdn.net/shang_xs/article/details/87874477
ThreadLocal和InheritableThreadLocal深入探究(二)在Spring中的应用
https://blog.csdn.net/shang_xs/article/details/87889219
ThreadLocal和InheritableThreadLocal深入探究(三)在Spring Cloud Netflix中的应用 > https://blog.csdn.net/shang_xs/article/details/87889285

猜你喜欢

转载自blog.csdn.net/shang_xs/article/details/87889079