ThreadLocal原理

概述

ThreadLocal直译为线程局部变量,或许将它命名为ThreadLocalVariable更为合适。其主要作用就是实现线程本地存储功能,通过线程本地资源隔离,解决多线程并发场景下线程安全问题。

API

实例

package com.starsray.test.tl;
 
import java.util.ArrayList;
import java.util.List;
 
public class ThreadLocalTest {
    // 声明一个ThreadLocal成员变量
    private final ThreadLocal<Person> tl = new ThreadLocal<>();
    // 声明一个List作为参照对象
    private final List<Person> list = new ArrayList<>();
 
 
    public static void main(String[] args) {
        new ThreadLocalTest().test();
    }
 
    public void test() {
        // 创建测试Person对象
        Person person = new Person();
        person.setName("张三");
        person.setAge(24);
        // 创建线程一:再启动1s后,分别添加person对象到tl、list对象中
        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            tl.set(person);
            list.add(person);
            System.out.println(Thread.currentThread().getName() + " [thread] get():" + tl.get());
            System.out.println(Thread.currentThread().getName() + " [list] get():" + list.get(0));
        },"thread-1").start();
 
        // 创建线程二:在启动2s后,分别去tl、list对象中取person对象
        new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " [thread] get():" + tl.get());
            System.out.println(Thread.currentThread().getName() + " [list] get():" + list.get(0));
        },"thread-2").start();
    }
    // 测试静态内部类Person
    static class Person {
        private String name;
        private int age;
 
        public void setName(String name) {
            this.name = name;
        }
 
        public void setAge(int age) {
            this.age = age;
        }
 
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
}

结果:

hread-1 [thread] get():Person{name='张三', age=24}
thread-1 [list] get():Person{name='张三', age=24}
thread-2 [thread] get():null
thread-2 [list] get():Person{name='张三', age=24}

分析:

看结果可以知道,线程之间的数据是隔离的,每个Thread维护了一份属于自己的数据。

原理分析

每个Thread对象都有一个ThreadLocalMap,当创建一个ThreadLocal时,就会将该ThreadLocal的ThreadLocalHashCode值(唯一)作为Key,数据作为Value存储在ThreadLocalMap中。也就是说数据其实都在Thread中。

向ThreadLocal存入一个值,实际上是向当前线程对象中的ThreadLocalMap存入值,ThreadLocalMap我们可以简单的理解成一个Map,而向这个Map存值的key就是ThreadLocal实例本身。

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);//获取当前Thread的ThreadLocalMap
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);//this就是当前ThreadLocal实例
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    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;//threadLocals就是Thread中ThreadLocalMap的变量名
    }

也就是说,想要存入的ThreadLocal中的数据实际上并没有存到ThreadLocal对象中去,而是以这个ThreadLocal实例作为key存到了当前线程中的一个Map中去了,获取ThreadLocal的值时同样也是这个道理。这也就是为什么ThreadLocal可以实现线程之间隔离的原因了。

应用场景

针对ThreadLocal而言,由于其适合隔离、线程本地存储等特性,因此天然的适合一些Web应用场景,比如下面所列举的例子:

  • 代替参数显式传递(很少使用,暂时不理解)

  • 存储全局用户登录信息

  • 存储数据库连接,以及Session等信息

  • Spring事务处理方案(暂时不理解)

总结

ThreadLocal的作用:实现线程范围内的局部变量,即ThreadLocal在一个线程中是共享的,在不同线程之间是隔离的。

ThreadLocal的原理:ThreadLocal存入值时使用当前ThreadLocal实例作为key,存入当前线程对象中的Map中去。

参考链接

https://blog.csdn.net/qq_38721537/article/details/124565091

https://blog.csdn.net/tianjindong0804/article/details/85597215

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值