美文网首页
ThreadLocal原理及继承功能实现

ThreadLocal原理及继承功能实现

作者: 码而优则仕 | 来源:发表于2020-04-12 20:20 被阅读0次

    多线程访问同一个共享共享变量时特别容易出现并发问题,特别是在多个线程需要对一个共享变量进行写入时。ThreadLocal是JDK包提供的,它提供了线程本地变量,也就是如果你创建一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的本地副本。当多个线程操作这个变量时,实际操作的是自己本地内存里面的变量。从而避免了线程安全问题。创建一个ThreadLocal变量后,每个线程都会复制一个变量到自己的本地内存。

    下面介绍ThreadLocal实现原理:

    先介绍相关的类和对象

    Thread类中有如下两个对象,都是ThreadLocalMap类型的,ThreadLocalMap是ThreadLocal内的内部类

     
        ThreadLocal.ThreadLocalMap threadLocals = null;
    
        ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    

    ThreadLocalMap是一个定制的HashMap,其Key就是ThreadLocal,Value就是用户存储的任意Object对象,如下为ThreadLocalMap的构造函数

     ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
                table = new Entry[INITIAL_CAPACITY];
                int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
                table[i] = new Entry(firstKey, firstValue);
                size = 1;
                setThreshold(INITIAL_CAPACITY);
            }
    
    

    默认ThreadLocalMap在Thread中为null,当程序线程第一次调用ThreadLocal的set()或者get()方法的时候进行初始化,如下是这两个方法的源码:

    set()及set()涉及的方法:
     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;
        }
    //////
      void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    

    代码先获取调用set方法的当前线程,然后获取当前线程的ThreadLocalMap值,如果为null就创建ThreadLocalMap,key就是当前类ThreadLocal对象的引用,value就是设置的值。如果不为空就直接设置值

    get()及get()涉及的方法
     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();
        }
    
    ///////////
     ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
    //////
       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;
        }
    

    代码也是首先获取调用get方法的线程,然后获取线程的ThreadLocalMap变量,如果为null就创建,如果不为null就直接获取值,获取值是根据ThreadLocal作为Key获取对应的Value。

    综上可知:ThreadLocal实现原理是每个线程维护一个特别定制的HashMap,线程调用ThreadLocal设置的值就是存放在各个线程的Map中,Map中的key就是用户线程new出来的ThreadLocal对象引用,value就是用户线程设置的值;用户线程通过ThreadLocal获取值的时候,先根据当前线程获取线程的HashMap,然后根据当前ThreadLocal对象实例引用作为key获取设置的value…所以ThreadLocal就只是充当了工具类的角色。线程设置的值就是存储在自己线程的本地内存中。

    上面讲解的是Thread类中的第一个变量,这个变量不支持继承,子线程不能查看父线程中设置的变量,而第二个变量就是为了解决这个问题设计的。

     
        ThreadLocal.ThreadLocalMap threadLocals = null;
    
        ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    

    代码如下:

     public Thread(Runnable target) {
            init(null, target, "Thread-" + nextThreadNum(), 0);
        }
    
    //////
    private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize) {
            init(g, target, name, stackSize, null, true);
        }
    ////////
      private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize, AccessControlContext acc,
                          boolean inheritThreadLocals) {
            if (name == null) {
                throw new NullPointerException("name cannot be null");
            }
    
            this.name = name;
    
            Thread parent = currentThread();
            SecurityManager security = System.getSecurityManager();
            if (g == null) {
                if (security != null) {
                    g = security.getThreadGroup();
                }
                if (g == null) {
                    g = parent.getThreadGroup();
                }
            }
            g.checkAccess();
            if (security != null) {
                if (isCCLOverridden(getClass())) {
                    security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
                }
            }
    
            g.addUnstarted();
    
            this.group = g;
            this.daemon = parent.isDaemon();
            this.priority = parent.getPriority();
            if (security == null || isCCLOverridden(parent.getClass()))
                this.contextClassLoader = parent.getContextClassLoader();
            else
                this.contextClassLoader = parent.contextClassLoader;
            this.inheritedAccessControlContext =
                    acc != null ? acc : AccessController.getContext();
            this.target = target;
            setPriority(priority);
            if (inheritThreadLocals && parent.inheritableThreadLocals != null)
                this.inheritableThreadLocals =
                    ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
            this.stackSize = stackSize;
            tid = nextThreadID();
        }
    

    以上线程构造函数的代码,ThreadLoca继承功能的实现就是在int()方法中实现的,其实原理很简单就是如果创建当前线程的线程(当前线程的父线程)中的ThreadLoclMap不为null,就作为入参新建一个子线程的Map这样线程子线程就拥有了父线程的值了。

    相关文章

      网友评论

          本文标题:ThreadLocal原理及继承功能实现

          本文链接:https://www.haomeiwen.com/subject/ignbmhtx.html