ThreadLocal使用及原理

一.简介及作用

    在一些场景中,我们希望一些变量只能被某个线程访问,对其他线程是隔离的,就需要用到ThreadLocal.

    ThreadLocal具有线程隔离性,用于解决多线程中相同变量的访问冲突问题.使每个线程读到的变量都是相独立的.线程内部变量仅相对于本线程而言可见.

二.简单使用

存储值,直接调用set()方法
取值,直接调用get()方法.

 ThreadLocal<String> threadLocal = new ThreadLocal<>();

        for (int i = 0; i < 5; i++) {
            String threadName = "Thread" + i;
            new Thread(() -> {
                threadLocal.set(threadName);
                System.out.println(threadName + "获取到值:" + threadLocal.get());
                threadLocal.remove();
            }, threadName).start();
        }

输出结果:
在这里插入图片描述

注意:针对同一个Thread,ThreadLocal 只能存储一个值,如下案例:
在这里插入图片描述

三.原理:

  1. 首先Thread有一个成员变量ThreadLocal.ThreadLocalMap,也就是每一个Thread都自身绑定了一个ThreadLocal.ThreadLocalMap.
    在这里插入图片描述

  2. 而ThreadLocal的静态内部类ThreadLocalMap,最主要的结构就是一个entry数组.
    在这里插入图片描述

  3. 在存储元素的时候,首先我们能根据当前thread获取到当前绑定的ThreadLocalMap,然后利用threadlocalMap中的threadLocalHashcode()方法计算出当前要存储的entry数组中的下标位置,key就是threadLocal对象,value就是要存的值,组成一个entry存进去.
    在这里插入图片描述

  4. 取元素的时候也是根据当前线程对象,拿到threadLocalMap,再根据this(threadLocal对象)计算hash值,找到下标,取值即可

四.自问自答

  1. 存储的数据结构是什么样的
    thread.ThreadLocal.ThreadLocalMap–>[<threadLocal1,value1>,<threadLocal2,value2>]

    数组中的下标就是通过当前threadLocal对象hash得到的.

  2. 为什么要传一个数组呢?
    对每一个线程来说,可能要存储的与之相关联的变量不只一个,所以必然需要一个集合去存储这些值.

  3. 当发生Hash冲突的时候是怎样处理的?
    ThreadLocal里面就有一个数组,不像hashMap,是数组+链表的结构,那么当ThreadLocal发生hash冲突的时候就会用到线性探测法,简单来说就是当冲突的时候,依次查找列表中离冲突单元最近的空闲单元,并且把新的键插入这个空闲单元.

  4. 为什么要用线性探测法?
        ThreadLocal 往往存放的数据量不会特别大(而且key 是弱引用又会被垃圾回收,及时让数据量更小),这个时候开放地址法简单的结构会显得更省空间,同时数组的查询效率也是非常高,加上第一点的保障,冲突概率也低

    开方地址法的缺点是容易产生堆积,不适用于大规模的存储.
    链地址法:不存在堆积问题,冲突处理简单,适合大数据存储.

  5. 为什么要是一个entry数组呢,不是一个单泛型得数组,比如说String数组?
        其实终其原因,是因为其在hash冲突的时候使用了线性探测法,会依次往后寻找空位置去插入,
    那么当我们去取值的时候,发生hash冲突,就得往后依次遍历比较哪一个是和我们存进去得key相等,才进行返回

今天的分享就到这里了,有问题可以在评论区留言,均会及时回复呀.
我是bling,未来不会太差,只要我们不要太懒就行, 咱们下期见.
在这里插入图片描述

ThreadLocalJava中的一个线程级别的变量,它提供了一种简单的方式来在多线程环境中维护变量的值。每个线程都拥有自己独立的ThreadLocal实例,并且可以通过该实例来获取和设置其对应的变量的值。 ThreadLocal原理是通过在每个线程中创建一个独立的副本来存储变量的值。这样,每个线程都可以独立地访问和修改自己的副本,而不会对其他线程产生影响。 ThreadLocal使用非常简单。首先,我们需要创建一个ThreadLocal对象,并指定要存储的变量类型。然后,我们可以通过调用ThreadLocal的get方法来获取当前线程中与该ThreadLocal对象关联的变量值,如果当前线程还没有设置过该变量,get方法会返回null。类似地,我们可以通过调用ThreadLocal的set方法来设置当前线程中与该ThreadLocal对象关联的变量值。 下面是一个简单的示例代码: ``` public class ThreadLocalExample { private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>(); public static void main(String[] args) { THREAD_LOCAL.set("Hello, world!"); Thread thread1 = new Thread(() -> { THREAD_LOCAL.set("Hello from thread 1!"); System.out.println(THREAD_LOCAL.get()); }); Thread thread2 = new Thread(() -> { THREAD_LOCAL.set("Hello from thread 2!"); System.out.println(THREAD_LOCAL.get()); }); thread1.start(); thread2.start(); System.out.println(THREAD_LOCAL.get()); } } ``` 在上面的示例中,我们创建了一个ThreadLocal对象`THREAD_LOCAL`用于存储String类型的变量。首先我们通过调用`THREAD_LOCAL.set("Hello, world!")`方法在主线程中设置了变量的值。然后,我们创建了两个新的线程并分别在其中设置了不同的值,并打印出来。最后,在主线程中我们也打印了变量的值。 运行上面的代码,你会看到输出结果类似于: ``` Hello from thread 1! Hello from thread 2! Hello, world! ``` 可以看到,每个线程都可以独立地访问和修改自己的变量副本,不会对其他线程产生影响。这样就确保了在多线程环境中,每个线程都可以维护自己的变量状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员bling

义父,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值