ThreadLocal说明

ThreadLocal说明

类ThreadLocal主要为了解决每个线程绑定自己的私有的值,可以吧ThreadLocal比如可全部存放的数据,每个线程都可以在里面存放自己的数据,并且不会和其他线程冲突。

测试代码

package com.zhoutao.demo.thread;

import java.util.concurrent.TimeUnit;

public class ThreadLocalDemo {

  public static ThreadLocal<String> threadLocal = new ThreadLocal();

  public static void main(String[] args) {
    // Initial value = null
    System.out.println("Initial Value = " + threadLocal.get());
    threadLocal.set("123");
    ThreadA threadA = new ThreadA();
    threadA.start();
    // 得到是123
    System.out.println("Main Get Value = " + threadLocal.get());
  }

  static class ThreadA extends Thread {

    @Override
    public void run() {
      ThreadLocalDemo.threadLocal.set("ABC");
      try {
        TimeUnit.SECONDS.sleep(2);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      // 得到的是ABC
      System.out.println("Thread A Get Value = " + ThreadLocalDemo.threadLocal.get());
    }
  }
}

观察下面的代码可以验证上面的结论,Main线程保存的是123,那么在子线程A保存"ABC" 后,获取也是"123",这样我们就可以验证上面的结论了,那么我们看下get() 方法的JDK源码是如何实现的.

源码分析

可以看到,其首先或者当前的线程t,使用线程t获取到了当前LocalMap(这个类没有继承Map接口),那么说明这个map对象是和当前线程t相关的。如果该对象不存在,那么返会setInitialVale()方法.该方法也是通过线程t获取当前map,map为空则执行createMap方法完成创建。

    /**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @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();
    }

    /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

   protected T initialValue() {
        return null;
    }

修改初始化值

在SetInitialValue方法中,可以看到其调用了initialValue方法进行了初始化,在代码1中

    // Initial value = null
    System.out.println("Initial Value = " + threadLocal.get());

可以看到没有设置初始值得情况下,其返回的是null,在上面的 protected T initialValue() 方法中也得到了验证,那么我们若要修改初始化值,仅要继承ThreadLocal类重写initialValue()方法即可,如下:

package com.zhoutao.demo.thread;

public class ThreadLocalExtend extends ThreadLocal<String> {

  @Override
  protected String initialValue() {
    return "DEFAULT INIT VALUE";
  }

  public static void main(String[] args) {
    ThreadLocalExtend extend = new ThreadLocalExtend();
    System.out.println("初始化值为:" + extend.get());
  }
}

从父线程继承数据

另外子线程也可以通过 InheritableThreadLocal 在子线程中获取从福线程继承下来的值。如上可以通过重写initialValue()方法修改初始化值,同时在可以获取父线程的数据的功能上,添加了通过childValue()方法修改从父线程获取的值,如:

package com.zhoutao.demo.thread;

public class InheritableThreadLocalExtend extends InheritableThreadLocal<String> {

  @Override
  protected String initialValue() {
      // 修改初始化值
    return "default init value";
  }

  @Override
  protected String childValue(String parentValue) {
    // 修改从父类获取的value
    return parentValue.toUpperCase();
  }

  public static void main(String[] args) {
    InheritableThreadLocalExtend extend = new InheritableThreadLocalExtend();
    System.out.println("初始化值为:" + extend.get());
  }
}
posted @ 2019-02-17 23:09  燕归来兮  阅读(328)  评论(0编辑  收藏  举报