ThreadLocal原理与使用


ThreadLocal是Java中的一个线程本地存储类,它可以用于将某个对象绑定到当前线程上。这样,在同一个线程中不同方法都可以访问到这个对象,而不需要将对象作为参数传递或者使用全局变量。

实现原理

ThreadLocal内部使用了一个ThreadLocalMap类来保存每个线程的值。ThreadLocalMap是一个使用线性探测法解决哈希冲突的哈希表,它的键值是ThreadLocal对象,值是对应线程中保存的对象。

当使用ThreadLocal.set方法设置一个值时,ThreadLocal首先获取当前线程,然后获取当前线程对应的ThreadLocalMap对象。ThreadLocalMap的getEntry方法使用ThreadLocal对象作为参数,返回当前线程中关联的Entry对象。如果Entry不存在,ThreadLocalMap就会使用ThreadLocal对象创建一个新的Entry并放到当前线程的ThreadLocalMap中。然后将需要保存的对象保存到Entry中。

当使用ThreadLocal.get方法获取值时,ThreadLocal还是会获取当前线程和对应的ThreadLocalMap对象,然后使用ThreadLocal对象作为参数调用ThreadLocalMap中的getEntry方法获取Entry。如果Entry不存在,ThreadLocalMap会使用ThreadLocal对象创建一个新的Entry并放到当前线程的ThreadLocalMap中。然后将新创建的Entry返回,Entry的getValue方法就可以返回之前保存的对象了。

ThreadLocal的存值操作

    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;
    }
    void createMap(Thread t, T firstValue) {
    
    
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

ThreadLocal的取值操作

    public T get() {
    
    
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
    
    
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
    
    
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

使用场景

ThreadLocal通常用于下列情况:

  1. 将一个普通变量保存到ThreadLocal中,使其在当前线程中随时可用,从而避免多次传参的麻烦。

  2. 将有状态的组件保存到ThreadLocal中,使得它们在第二次使用时可以避免重复初始化,从而提高性能和效率。

  3. 实现线程安全的单例模式,通过ThreadLocal来保证每个线程内只有一个实例。

ThreadLocal使用需要注意的点

  1. 内存泄漏:ThreadLocalMap中的Entry对象是弱引用,只有在当前线程存活期内且该线程的ThreadLocalMap存在时,则Entry对象才不会被回收。如果ThreadLocal没有及时地被回收,会导致Entry对象无法回收,进而导致内存泄漏问题。

    扫描二维码关注公众号,回复: 15511107 查看本文章
  2. 释放资源:使用ThreadLocal时需要手动调用remove方法来清除保存在线程中的对象,以免造成资源的浪费。

  3. 线程不安全:ThreadLocal只是用来保存本线程中的数据,因此在并发的情况下,每个线程都有自己的变量副本,因此不会发生线程安全的问题。但是,如果多个线程共用一个ThreadLocal,那么仍然会出现线程安全的问题。

猜你喜欢

转载自blog.csdn.net/weixin_43598687/article/details/131390122