首页 > 其他分享 >ThreadLocal

ThreadLocal

时间:2023-07-12 16:55:56浏览次数:29  
标签:ThreadLocalMap int ThreadLocal 线程 key table

ThreadLocal类主要解决的就是让每个线程绑定自己的值,可以存储每个线程的私有数据。

如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的本地副本。

Thread 类

public class Thread implements Runnable {
    //......
    //与此线程有关的ThreadLocal值。由ThreadLocal类维护
    ThreadLocal.ThreadLocalMap threadLocals = null;

    //与此线程有关的InheritableThreadLocal值。由InheritableThreadLocal类维护
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    //......
}

ThreadLocal 类的 set() 方法

public void set(T value) {
    //获取当前请求的线程
    Thread t = Thread.currentThread();
    //取出 Thread 类内部的 threadLocals 变量(哈希表结构)
    ThreadLocalMap map = getMap(t);
    if (map != null)
        // 将需要存储的值放入到这个哈希表中
        map.set(this, value);
    else
        createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

最终的变量是放在了当前线程的 ThreadLocalMap,并不是存在 ThreadLocal 上,ThreadLocal 可以理解为只是ThreadLocalMap的封装,传递了变量值。 ThrealLocal 类中可以通过Thread.currentThread()获取到当前线程对象后,直接通过getMap(Thread t)可以访问到该线程的ThreadLocalMap对象。

 

ThreadLocal 使用示例

ThreadLocalMap 类的定义在 ThreadLocal<T> 类中,是 ThreadLocal 类的一个内部类, key 是 ThreadLocal<T> 的一个对象,value 是这个 <T> 的实际值

Thread 线程类有一个字段,ThreadLocal.ThreadLocalMap threadLocals = null,是 ThreadLocal.ThreadLocalMap 类的一个实现对象,也就是每个线程对象都有一个 ThreadLocalMap 对象

ThreadLocal<T> 相当于一个维护所有线程 ThreadLocal.ThreadLocalMap threadLocals = null 这个属性,即所有线程 <T> 的取值 value 的一个工具类

下面用一个例子说明这一点

import dto.TreeNode;

import java.util.Random;

public class testThreadLocal implements Runnable{

    private static final ThreadLocal<TreeNode> treeNodeThreadLocal = new ThreadLocal<>();

    private static final ThreadLocal<Integer> integerThreadLocal = new ThreadLocal<>().withInitial(() -> 0);

    public static void main(String[] args) throws InterruptedException {
        testThreadLocal thisclass = new testThreadLocal();
        for(int i=0 ; i<10; i++){
            Thread t = new Thread(thisclass, ""+i);
            Thread.sleep(new Random().nextInt(1000));
            t.start();
        }
    }

    @Override
    public void run() {
        System.out.println("Thread Name= "+Thread.currentThread().getName()+" integerThreadLocal = "+ integerThreadLocal.get());
        Integer curThreadInt = new Random().nextInt(1000);
        treeNodeThreadLocal.set(new TreeNode(curThreadInt, Thread.currentThread().getName()));
        integerThreadLocal.set(curThreadInt);

        System.out.println("Thread Name= "+Thread.currentThread().getName()
                +" integerThreadLocal = "+integerThreadLocal.get()
                +" treeNodeThreadLocal = "+treeNodeThreadLocal.get());
    }

}

输出结果如下

treeNodeThreadLocal 和 integerThreadLocal 这两个 ThreadLocal 类的对象与线程的关系如下所示

ThreadLocal. ThreadLocalMap 内部类定义

/**
     * ThreadLocalMap is a customized hash map suitable only for
     * maintaining thread local values. No operations are exported
     * outside of the ThreadLocal class. The class is package private to
     * allow declaration of fields in class Thread.  To help deal with
     * very large and long-lived usages, the hash table entries use
     * WeakReferences for keys. However, since reference queues are not
     * used, stale entries are guaranteed to be removed only when
     * the table starts running out of space.
     */
    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;

        /**
         * The number of entries in the table.
         */
        private int size = 0;

        /**
         * The next size value at which to resize.
         */
        private int threshold; // Default to 0

        /**
         * Set the resize threshold to maintain at worst a 2/3 load factor.
         */
        private void setThreshold(int len) {
            threshold = len * 2 / 3;
        }

        /**
         * Increment i modulo len.
         */
        private static int nextIndex(int i, int len) {
            return ((i + 1 < len) ? i + 1 : 0);
        }

        /**
         * Decrement i modulo len.
         */
        private static int prevIndex(int i, int len) {
            return ((i - 1 >= 0) ? i - 1 : len - 1);
        }

        /**
         * Construct a new map initially containing (firstKey, firstValue).
         * ThreadLocalMaps are constructed lazily, so we only create
         * one when we have at least one entry to put in it.
         */
        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);
        }

        /**
         * Construct a new map including all Inheritable ThreadLocals
         * from given parent map. Called only by createInheritedMap.
         *
         * @param parentMap the map associated with parent thread.
         */
        private ThreadLocalMap(ThreadLocalMap parentMap) {
            Entry[] parentTable = parentMap.table;
            int len = parentTable.length;
            setThreshold(len);
            table = new Entry[len];

            for (int j = 0; j < len; j++) {
                Entry e = parentTable[j];
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                    if (key != null) {
                        Object value = key.childValue(e.value);
                        Entry c = new Entry(key, value);
                        int h = key.threadLocalHashCode & (len - 1);
                        while (table[h] != null)
                            h = nextIndex(h, len);
                        table[h] = c;
                        size++;
                    }
                }
            }
        }

        /**
         * Get the entry associated with key.  This method
         * itself handles only the fast path: a direct hit of existing
         * key. It otherwise relays to getEntryAfterMiss.  This is
         * designed to maximize performance for direct hits, in part
         * by making this method readily inlinable.
         *
         * @param  key the thread local object
         * @return the entry associated with key, or null if no such
         */
        private Entry getEntry(ThreadLocal<?> key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }

        // ...... 后面的就不贴过来了

 

标签:ThreadLocalMap,int,ThreadLocal,线程,key,table
From: https://www.cnblogs.com/suBlog/p/17547959.html

相关文章

  • Hystrix传播ThreadLocal对象,Feign调用返回null问题
    微服务与微服务之间相互调用,你是否有过使用Hystrix时,该传播ThreadLocal对象的困惑?  我们知道Hystrix有隔离策略:THREAD(线程池隔离):即:每个实例都增加个线程池进行隔离SEMAPHORE(信号量隔离):适应非网络请求,因为是同步的请求,无法支持超时,只能依靠协议本身   现在有如下两......
  • Python 实现 ThreadLocal
    importthreadingfromthreadingimportget_identimporttimeclassContext:def__init__(self):object.__setattr__(self,'__global_context__',dict())object.__setattr__(self,'__get_ident__',get_ident)def......
  • ThreadLocal
    ThreadLocal慕课网教程多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal是除了加锁这种同步方式之外的一种保证一种规避多线程访......
  • ThreadLocal源码
    使用场景ThreadLocal用来提供线程局部变量。每个线程都会有一份独立的副本,副本之间不存在竞争关系,是线程专属的内存空间。例如:publicclassThreadLocalTest{privatestaticfinalThreadLocal<Integer>threadLocal=newThreadLocal<>();publicstaticvoidma......
  • 深入理解 Java 中的 ThreadLocal
    1.什么是ThreadLocal在Java多线程编程中,我们经常会遇到共享变量的并发访问问题。为了解决这个问题,Java提供了ThreadLocal类,它允许我们在每个线程中存储和访问线程局部变量,而不会影响其他线程的数据。2.使用ThreadLocal使用ThreadLocal很简单,我们只需要创建一个Thre......
  • ThreadLocal
    关于ThreadLocal介绍ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是privatestatic类型的,用于关联线程和线程上下文。作用提供线程内的局部变量,不......
  • Java并发工具之ThreadLocal
    一、ThreadLocal简介1.ThreadLocal是什么?ThreadLocal字面意思是本地线程,其实更准确来说是线程局部变量,线程类Thread有个变量叫做threadLocals,其类型就是ThreadLocal.ThreadLocalMap类型,他其实不是一个Map类型,但可以暂时理解它是一个Map,键为ThreadLocal对象,值就是要......
  • ThreadLocal 与 synchronized 区别
    老实说,从看到这个帖子的题目开始,就觉得帖子的作者估计是在概念上有所混淆了,于是乎想写个咚咚,同大家分享一下自己的心得。帖子上,讨论的人很多,高手不乏,各抒己见,但不知新手们看明白没有,因此,这里偶以最简洁列表方式来说一说相关问题。1.区别ThreadLocal与synchronizedThread......
  • 图解ThreadLocal
    ThreadLocalTestpublicclassThreadLocalTest{publicstaticvoidmain(String[]args){ThreadLocalthreadLoal_1=newThreadLocal();newThread(()->{threadLoal_1.set("hellot1");System.out.print......
  • 深入学习ThreadLocal
    1、用来干吗的?用于线程在任意的地方去共享数据,而不被其他线程所干扰,2、原理是什么因为每个线程维护一份ThreadLocalMap,使用threadlocal.set(obj)方法是存放在map里面的Entry<<WeekReference>ThreadLocal,Value>数组里3、实际案例,比如写了util类,但是SimplateDateFormate是线程......