ThreadLocal使用

1 ThreadLocal

原文:https://blog.csdn.net/bfj11/article/details/122560696

ThreadLocal是Java 内部提供的 解决 多线程之间 线程隔离的 技术。多线程情况下,同一个 ThreadLocal 变量 对 每一个线程而言 都是 仅自己可见,线程隔离的。

1.1 基本使用

  • 定义ThreadLocal

    //通常ThreadLocal都是 private static final 的
    private static final ThreadLocal<String> tl = new ThreadLocal<>();
    
  • 编辑、获取、删除

    //每一个ThreadLocal只能设置一个值,多个值以最后一个为准
    // 每一个线程在同一个ThreadLocal中设置的值不会被其他线程操作
    t1.set("peiqi"); 
    t.get();
    t.remove();
    
  • 初始值设置

    // ThreadLocal 的默认值是 null,可通过子类继承的方式实现 initialValue()设置
    new ThreadLocal<String>(){
        @Override
        protected String initialValue() { //该方法是延迟加载的,只有 未使用set之前使用get就会执行该方法返回
            return "peiqi";
        }
    };
    

1.2 原理

在每一个Thread 中都 维护了 一个 ThreadLocalMap 对象,该对象的键 是 ThreadLocal,值是 当前线程在 该ThreadLocal 设置的值

  • ThreadLocalMap类 并不 实现 Map接口,是单独实现在 ThreadLocal 类中,是ThreadLocal 类的 静态内部类
  • ThreadLocalMap类 其内部的Entry也是独立实现

ThreadLocal的操作中,都会 通过 Thread.currentThread() 获取 当前线程,再 通过 getMap(t)获取该 ThreadLocalMap对象

  • ThreadLocal的set(val)

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t); // 从线程t中获取 ThreadLocalMap对象
        if (map != null)
            map.set(this, value);// 将threadlocal对象、值作为键值对存入
        else
            createMap(t, value);// 以 threadlocal对象、值作为 初始键值对 初始化 ThreadLocalMap 对象
    }
    
  • ThreadLocal的get(val)

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t); // 从线程t中获取 ThreadLocalMap对象
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);//根据threadlocal对象获取 键值对
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value; //键值对中获取value
                return result;
            }
        }
        return setInitialValue();// 该方法中执行 initialValue()方法获取初始值,再将初始值存放到map(map不存在就初始map)
    }
    
  • ThreadLocal的remove()

    public void remove() {
        ThreadLocalMap m = getMap(Thread.currentThread()); // 从线程t中获取 ThreadLocalMap对象
        if (m != null)
            m.remove(this); //找到该 threadlocal的数组索引位置并删除
    }
    

1.3 注意点

使用完ThreadLocal后,记得 使用remove()方法防止内存泄露问题

t.remove()

1.4 使用场景

  • 事务操作

    比如银行的 转账业务,扣钱与加钱方法的过程应该在同一事务进行,这时可以使用 ThreadLocal 保证 持久层和 服务层 使用同一个 connection对象

posted @ 2023-08-07 09:46  让时间变成力量  阅读(75)  评论(0)    收藏  举报