ThreadLocal介绍

作者: 喏喏2021 | 来源:发表于2022-02-02 23:56 被阅读0次

1. 简单使用

package thread;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class ThreadLocalTest {
       //定义一个threadLocal共享亦是
    private static final ThreadLocal<String> userIdThreadLocal = new ThreadLocal<String>();
    public static void main(String[] args) {
        String mainUserId = UUID.randomUUID().toString();
        System.out.println("main thread userId set:" + mainUserId);
        //主线程中设置userId
        userIdThreadLocal.set(mainUserId);
        
        Thread t1 = new Thread(()->{
            String t1UserId = UUID.randomUUID().toString();
            System.out.println("t1 thread userId set:" + mainUserId);
            //t1线程中设置userId
            userIdThreadLocal.set(t1UserId);
            try {
                TimeUnit.MICROSECONDS.sleep(2);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //t1线程中打印userId
            System.out.println("t1 thread userId get:" + userIdThreadLocal.get());
        });
        t1.start();
        //主线程中打印userId
        System.out.println("main thread userId get:" + userIdThreadLocal.get());
    }
}
//main thread userId set:c7eee748-a2af-4686-9b26-ba930aa3c2fd
//main thread userId get:c7eee748-a2af-4686-9b26-ba930aa3c2fd
//t1 thread userId set:c7eee748-a2af-4686-9b26-ba930aa3c2fd
//t1 thread userId get:b43f281f-19b0-4b4f-92b4-3f10cba3612d

可以看到,同一个线程中设置完userId,在线程中的其他地方可以读取出来使用

2. 实现原理

我们先看一下ThreadLocal中,上面用到的两个方法:get(),set()
这里我们要先看一个ThreadLocal中的嵌套类ThreadLocalMap

static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal> {
            /** The value associated with this ThreadLocal. */
            Object value;

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

        /**
         * The initial capacity -- MUST be a power of two.
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
        private Entry[] table;
}

说明:

  1. 我们可以看到ThreadLocalMap内部还嵌套了一个Entry的内部类,它是继承了弱引用,Entry本身只有一个value值
  2. ThreadLocalMap中,有一个Entry类型的数组,Entry[] table,这里保存着各ThreadLocal的key,以及对应的value值

下面再看一下这两个方法:

/**
     * 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);  //根据线程获得threadLocalMap变量
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this); //获得当前threadlocal对应的entry值
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result; //返回entry中的value值
            }
        }
        return setInitialValue();
    }
/**
     * 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); //返回当前线程中的threadlocalMap变量
        if (map != null)
            map.set(this, value); //根据当前threadlocal键,设置value值
        else
            createMap(t, value);
    }

从上面可以看出,我们根据线程,就可以得到threadLocalMap变量,
我们看一下线程的源码可以看到如下两行定义:


image.png

也就是说,实际threadLocalMap值是存储在当前线程中的

3. 总结

  1. 与synchronized锁的机制不同,threadLocal主要是在每个线程中保存着一份entry值,包含着当前threadlocal和对应的value值
  2. 每次取值时,都可以从当前线程的threadLocalMap中,根据threadLocal取得对应的value值

相关文章

  • 大话 ThreadLocal

    概述 ThreadLocal 介绍 ThreadLocal 关键方法讲解 ThreadLocalMap 内部类介绍...

  • ThreadLocal原理介绍以及内存泄漏分析

    ThreadLocal简单介绍 ThreadLocal同ReentrantLock,CyclicBarrier等都...

  • Looper场景ThreadLocal原理分析

    ThreadLocal介绍 ThreadLocal支持泛型,ThreadLocal,T代表的是线程本地变量,...

  • 聊一聊我眼中的ThreadLocal(面试题形式总结)

    这篇总结一下 ThreadLocal,主要的议题有: ThreadLocal 介绍 ThreadLocal 实现原...

  • ThreadLocal介绍

    ThreadLocal简介 ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数...

  • ThreadLocal介绍

    我们在说明handler原理和AsyncTask原理的时候都提到了ThreadLocal,当时没有细说,现在来介绍...

  • ThreadLocal介绍

    ThreadLocal,顾名思义,其存储的内容是线程本地的,私有的,我们常用来存储和维护一些资源或者变量,以避免线...

  • ThreadLocal介绍

    ThreadLocal 能做什么 ThreadLocal 是 JDK 提供的一个工具类,它可以为每个使用它的线程创...

  • 介绍ThreadLocal

    1、概览 在本文中,我们将研究下ThreadLocal。ThreadLocal为我们提供了为当前线程单独保存数据的...

  • ThreadLocal介绍

    1. 简单使用 可以看到,同一个线程中设置完userId,在线程中的其他地方可以读取出来使用 2. 实现原理 我们...

网友评论

    本文标题:ThreadLocal介绍

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