ThreadLocal详解2

ThreadLocal详解2

本篇博文为转载,转载连接:https://www.cnblogs.com/dreamroute/p/5034726.html

ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。

这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常使用,比如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。这种情况,ThreadLocal就比较好的解决了这个问题。

我们从源码的角度来分析这个问题。

首先定义一个ThreadLocal[完整代码查看本地工具类E盘]:

public final class ConnectionUtil {

    private ConnectionUtil() {}

    private static final ThreadLocal<Connection> conn = new ThreadLocal<>();

    public static Connection getConn() {
        Connection con = conn.get();
        if (con == null) {
            try {
                Class.forName("com.mysql.jdbc.Driver");
                con = DriverManager.getConnection("url", "userName", "password");
                conn.set(con);
            } catch (ClassNotFoundException | SQLException e) {
                // ...
            }
        }
        return con;
    }

}

这样子,都是用同一个连接,但是每个连接都是新的,是同一个连接的副本。

那么实现机制是如何的呢?

1、每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocal的Map,可以存放若干个ThreadLocal。

/* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

2、当我们在调用get()方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap对象,如果非空,那么取出ThreadLocal的value,否则进行初始化,初始化就是将initialValue的值set到ThreadLocal中。

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

3、当我们调用set()方法的时候,很常规,就是将值设置进ThreadLocal中。

4、总结:当我们调用get方法的时候,其实每个当前线程中都有一个ThreadLocal。每次获取或者设置都是对该ThreadLocal进行的操作,是与其他线程分开的。

5、应用场景:当很多线程需要多次使用同一个对象,并且需要该对象具有相同初始化值的时候最适合使用ThreadLocal。

6、其实说再多也不如看一下源码来得清晰。如果要看源码,其中涉及到一个WeakReference和一个Map,这两个地方需要了解下,这两个东西分别是a.Java的弱引用,也就是GC的时候会销毁该引用所包裹(引用)的对象,这个threadLocal作为key可能被销毁,但是只要我们定义成他的类不卸载,tl这个强引用就始终引用着这个ThreadLocal的,永远不会被gc掉。b.和HashMap差不多。

事实上,从本质来讲,就是每个线程都维护了一个map,而这个map的key就是threadLocal,而值就是我们set的那个值,每次线程在get的时候,都从自己的变量中取值,既然从自己的变量中取值,那肯定就不存在线程安全问题,总体来讲,ThreadLocal这个变量的状态根本没有发生变化,他仅仅是充当一个key的角色,另外提供给每一个线程一个初始值。如果允许的话,我们自己就能实现一个这样的功能,只不过恰好JDK就已经帮我们做了这个事情。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadLocal是一种与线程绑定的变量,它可以解决多线程并发访问的问题。与Synchronized不同,ThreadLocal为每个线程提供了一个独立的变量副本,每个线程都可以独立地修改自己的副本,而不会影响其他线程的副本。 ThreadLocal的使用方法比较简单。我们可以通过ThreadLocal类的set()方法来设置当前线程所关联的变量的值,通过get()方法来获取当前线程所关联的变量的值。在使用完ThreadLocal后,如果不再需要这个变量,应该调用remove()方法来清除当前线程的关联变量,避免内存泄漏的问题。 ThreadLocal的原理是通过每个线程都拥有一个独立的ThreadLocalMap对象来实现的。ThreadLocalMap内部使用一个Entry数组来存储键值对,键为ThreadLocal对象,值为对应的变量副本。在获取当前线程所关联的变量时,会根据ThreadLocal对象找到对应的变量副本并返回。ThreadLocal与Thread、ThreadLocalMap之间的关系是,每个线程都有一个ThreadLocalMap对象,其中存储了与该线程关联的所有ThreadLocal对象及其对应的变量副本。 ThreadLocal的常见使用场景包括但不限于: - 解决线程安全问题:可以将需要在多个线程中共享的数据存储在ThreadLocal变量中,每个线程访问自己的变量副本,避免了线程安全问题。 - 传递上下文信息:可以将一些需要在多个方法中共享的上下文信息存储在ThreadLocal变量中,在方法调用链中方便地获取这些上下文信息。 - 数据库连接管理:可以将数据库连接存储在ThreadLocal变量中,在每个线程中独立管理数据库连接,避免了线程间的冲突。 总之,ThreadLocal提供了一种方便的方式来实现线程间的数据隔离和传递,能有效地解决多线程并发访问的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [史上最全ThreadLocal 详解](https://blog.csdn.net/qq_43842093/article/details/126715922)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [ThreadLocal详解](https://blog.csdn.net/m0_49508485/article/details/123234587)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值