当前位置:   article > 正文

ThreadLocal源码分析_theadlocal变量可见性

theadlocal变量可见性

并发基础概念

并发:是指同一个时间段内多个任务同时在执行。并且都没有执行结束
并行:是指单位时间内多个任务同时执行

多线程安全问题

多线程访问同一个共享时特别容易出现并发问题,特别实在多个线程需要一个共享变量进行写时,为了保证线程安全。需要对共享变量进行同步

解决线程安全问题

1、保证内存可见性和原子操作;synchronized两者皆可保证。volatile关键字只能保证内存可见性

2、变量不共享在多线程

ThreadLocal用概述

创建一个TheadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本。

Thead ThreadLocal ThreadLocalMap关系

关系图
在这里插入图片描述
ThreadLocalMap实体类是ThreadLocal内部类,ThreadLocalMap内部数据结构是Entry数组。其中key存放ThreadLocal。value存放具体的变量值。

类图
在这里插入图片描述

Entry实体类是TheadLocalMap内部类。ThreadLocalMap实体类是ThreadLocal内部类。ThreadLocalMap在Thread实体类是一个变量。

ThreadLocalMap 源码分析

Entry类

  static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Entry类继承WeakReference。表示K是一个弱引用。其目的是方便JVM 回收。

ThreadLocalMap 类

ThreadLocalMap 是一个Map数据结构,采用的键值对存储数据。table数组变量用于存储。

  private Entry[] table;
  • 1

ThreadLocalMap

 private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

ThreadLocalMap 和 HashMap 都是采用Map键值对数据结构。但是二者解决Hash冲突的方式不一样。HashMap采用的是链地址法(数组+链表)。ThreadLocalMap 采用的开法地址法

Hash冲突解决方式

ThreadLocal 源码分析

首先是一个无参的构造函数

 /**
     * Creates a thread local variable.
     * @see #withInitial(java.util.function.Supplier)
     */
    public ThreadLocal() {
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

set方法

   /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  1. 获取当前线程对象实例t 获取当前线程t,
  2. 本地线程变量集合map
  3. 如果当前集合map存在。则值修改value值
  4. 如果不存在,则创建线程本地变量Map

get 方法

    /**
     * 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();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

获取当前线程对象实例t
本地线程变量集合map
如果Map不等于null,根据ThreadLocal。获取value

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/294557
推荐阅读
相关标签
  

闽ICP备14008679号