ThreadLocal 原理与基本使用

ThreadLocal基本使用

保证多个线程对变量访问的安全,将变量放到ThreadLocal类型的对象中,使变量在每个线程中都有独立值,不会出现一个线程读取变量时被另一个线程修改的现象。
使用示例

public class testThreadLocal {
    public static void main(String[] args) {
        ThreadLocal<String> local = new ThreadLocal<>();
        Random random = new Random();
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    local.set(Thread.currentThread().getName()+"......"+ random.nextInt(10));
                    System.out.println("线程和local值分别是"+local.get());
					local.remove();
                }
            }).start();

        }

    }
}

使用场景:

  • 线程隔离,ThreadLocal的数据只属于当前线程,多线程情况下可以防止自己的变量被其他线程篡改,常用案例,每个线程绑定一个用户会话信息,数据库连接,HTTP请求等,这样每个线程调用到的处理函数都可以非常方便的访问这些资源。数据库连接独享,Session数据管理
  • 跨函数传递数据,同一个线程内跨类,夸方法传递数据时,如果不用ThreadLocal,那么相互之间的数据传递势必要靠返回值和参数,增加了这些类或方法的耦合度。

推荐使用static final修饰ThreadLocal 对象 被所有对象共享,防止使用过程中发生动态变更;

源码分析

  • Thread类有一个threadLocals 变量 使用默认访问控制修饰符,包内可见
/* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
     // 翻译下:此线程相关的本地变量值,此map由ThreadLocal类维护,初始值为空
    ThreadLocal.ThreadLocalMap threadLocals = null;
  • ThreadLocal类结构
    在这里插入图片描述
  • set(T value) 方法

public void set(T value) {
		//获取当前线程
        Thread t = Thread.currentThread();
        //获取线程的map
        ThreadLocalMap map = getMap(t);
        //value值方入map
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    
//根据线程对象获取其属性 threadLocals
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    //创建ThreadLocalMap 对象
 void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }


  • get() 方法
public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        	// 根据threadLocal对象获取 Entry
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //如果map为空 返回初始值null
        return setInitialValue();
    }

 private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }


protected T initialValue() {
        return null;
    }
  • remove() 方法
public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

内容泄露问题:

  • map中的key为什么是弱引用?
    线程执行过程,调用栈内变量t 强引用指向 堆内对象LocalThread 而线程中threalocaltMap 中的key是弱引用ThreadLocal对象,不能是强引用,会造成内容泄露;因为线程执行完成 栈内变量t会销毁,但线程不一定会销毁,线程中的threadlocalmap对应也不一定会销毁,造成内存泄漏,此时如果key是强引用ThreadLocal对象,则ThreadLocal对象无法销毁,LocalThread对象不能被垃圾回收,故一定要弱引用;

  • 线程变量使用完后,使用remove清除 map中的value,避免内存泄漏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值