zoukankan      html  css  js  c++  java
  • 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());
      }
    }
    
  • 相关阅读:
    Oracle建立表空间和用户
    Session详解
    Spring中AOP方式实现多数据源切换
    Filter(过滤器)学习
    不用加号运算
    数字转化为十六进制
    1px像素问题(移动端经典问题)
    对postcss-plugin-px2rem的研究
    npm cache clean --force
    对async/await的研究
  • 原文地址:https://www.cnblogs.com/zhoutao825638/p/10393202.html
Copyright © 2011-2022 走看看