并发之ThreadLocal学习


前言

一、基础介绍

1、ThreadLocal的定义

ThreadLocal是线程Thread中属性threadLocals的管理者。
ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

2、 使用场景

ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景。

3、ThreadLocal原理

3.1、ThreadLocal类结构及方法解析

在这里插入图片描述

3.2、ThreadLocal及Thread之间的关系

在这里插入图片描述

Thread中属性threadLocals,作为一个特殊的Map,它的key值就是我们ThreadLocal实例,而value值这是我们设置的值。

3.3 、ThreadLocal的set()方法

public void set(T value) {
        //1、获取当前线程
        Thread t = Thread.currentThread();
        //2、获取线程中的属性 threadLocalMap ,如果threadLocalMap 不为空,
        //则直接更新要保存的变量值,否则创建threadLocalMap,并赋值
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            // 初始化thradLocalMap 并赋值
            createMap(t, value);
    }

3.4、 ThreadLocal的get方法

 public T get() {
        //1、获取当前线程
        Thread t = Thread.currentThread();
        //2、获取当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //3、如果map数据为空,
        if (map != null) {
            //3.1、获取threalLocalMap中存储的值
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //如果是数据为null,则初始化,初始化的结果,TheralLocalMap中存放key值为threadLocal,值为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;
    }

3.5 、ThreadLocal的remove方法

public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

二、使用场景

1、数据库连接保证线程安全

2、存储用户Session

private static final ThreadLocal threadSession = new ThreadLocal();
 
    public static Session getSession() throws InfrastructureException {
        Session s = (Session) threadSession.get();
        try {
            if (s == null) {
                s = getSessionFactory().openSession();
                threadSession.set(s);
            }
        } catch (HibernateException ex) {
            throw new InfrastructureException(ex);
        }
        return s;
    }

3、数据跨层传递(controller,service, dao)

public class ActionDataManager {
    
        /*请求头参数*/
        ThreadLocal<String> headThreadLocal = new ThreadLocal<String>();
        /*请求体参数*/
        ThreadLocal<String> bodyThreadLocal = new ThreadLocal<String>();
        
}
//统一HTTP请求接口处理
class HttpController{
    public void process(...){
    	解析参数...
    	
        //给ThreadLocal赋值,后续的服务直接通过ThreadLocal获取就行了。
        ActionDataManager .headThreadLocal .set(head);
        new Service().service();
    }
}
class Service{
    public void service(){
        String head =  ActionDataManager .headThreadLocal .get();
     	...
    }
}

三、使用注意

1、 各种引用与GC的关系

类型回收时间应用场景
强引用一直存活,除非GC Roots不可达所有程序的场景,基本对象,自定义对象等
软引用内存不足时会被回收一般用在对内存非常敏感的资源上,用作缓存的场景比较多,例如:网页缓存、图片缓存
弱引用只能存活到下一次GC前生命周期很短的对象,例如ThreadLocal中的Key。
虚引用随时会被回收, 创建了可能很快就会被回收可能被JVM团队内部用来跟踪JVM的垃圾回收活动

2、使用ThreadLocal可能导致的内存泄漏

因为ThreadLocal在ThreadLocalMap中作为key时是弱应用WeakReference,所以可能导致key被回收,而值无法再使用导致内存泄漏。

  • ThreadLocal引用被设置为null,且后面没有set,get,remove操作。
  • 线程一直运行,不停止。(线程池)
  • 触发了垃圾回收。(Minor GC或Full GC)

避免ThreadLocal导致内存泄漏的方法:

  • ThreadLocal申明为private static final。
    Private与final 尽可能不让他人修改变更引用,
    Static 表示为类属性,只有在程序结束才会被回收。

  • ThreadLocal使用后务必调用remove方法。
    最简单有效的方法是使用后将其移除。

3、ThreadLocal与Synchronized的区别

ThreadLocal其实是与线程绑定的一个变量。ThreadLocal和Synchonized都用于解决多线程并发访问。

但是ThreadLocal与synchronized有本质的区别:

  1. Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
  2. Synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

today_code_logs

做最明亮的自己,然后照亮他人

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

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

打赏作者

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

抵扣说明:

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

余额充值