行业资讯 2025年08月6日
0 收藏 0 点赞 757 浏览 2114 个字
摘要 :

文章目录 ThreadLocal实现线程绑定 ThreadLocal是如何做到线程绑定的呢? 本文主要讲解关于ThreadLocal实现线程绑定相关内容,让我们来一起学习下吧! ThreadLocal实现……




本文主要讲解关于ThreadLocal实现线程绑定相关内容,让我们来一起学习下吧!

ThreadLocal实现线程绑定

为了实现数据库事务管理,多条sql请求应当使用同一个Connection,然而事务控制包含处理逻辑,应属于服务层,而SQL请求属于dao层,于是乎,就有了这样一条需求:在不同的类中都可以拿到同一个对象实例,但不同的线程取到的实例不同我们将这种数据称之为线程本地变量,这种操作叫做线程绑定

可见需求分为两部分,一、不通过传参实现在不同的类中获得相同的实例,二、实例与线程对应,同一个线程获取到的是同一个实例,不同线程获取到的却不能相同。

怎么实现“不通过传参,在任意位置获取同一个实例”

对于第一点很好保证,通过将变量赋值给类的静态成员,这样在其他类中就可以通过类名获取到数据。我们还可以将这个类抽取为工具类,如下:

public class BindUtils {
    private static MyData myData;

    public static MyData getMyData(){
        if(myData==null){
            synchronized(BindUtils.class) {
                if(myData==null) {
                    myData = new MyData();
                }
            }
        }
        return myData;
    }
}

// 这样就可以在其他类中,任意位置获取到MyData这个变量了。
class OtherClass1{
    void xxxfunc(){
        BindUtils.getMyData();
    }
}

但是显然MyData属于类的静态成员,在堆内存中,被所有的线程共享,不同的线程拿到的myData肯定是同一个。

怎么实现“不同的线程获取到不同的实例”

在前者的基础上使用ThreadLocal改造即可:

public class BindUtils {
    private static ThreadLocal<MyData> tl = new ThreadLocal<>();

    public static MyData getMyData() {
        if (tl.get() == null) {
           tl.set(new MyData());
        }
        return tl.get();
    }
}

ThreadLocal是如何做到线程绑定的呢?

每个线程都有一个Thread实例,Thread类中有一个成员变量threadLocals,该变量类似于一个Map集合。其中可以保存键值对。由于它是成员变量,所以每个Thread实例互不相同,二每个Thread实例对应各自的线程,所以将数据放到threadLocals里,就实现了与线程绑定。

然而threadLocals并不是真正的map集合,我们也无法直接操作。所以把数据放进去和取出来都需要通过ThreadLocal操作。调用ThreadLocal的set方法,可以将数据放入,放入时以ThreadLocal实例【此处为 tl】为键,以要存入的数据为值。get取出数据时也是以自身为键,取出对应的值。

打个比方就是:每个线程都有一个仓库threadLocals,ThreadLocal的实例就像是一个令牌,拿着令牌就可以把一样东西存入仓库,同样还是呀拿着这个令牌就能把货物从仓库取出。由于每个线程一个仓库,所以不同的线程拿着相同的令牌取出的东西也不同。

所以现在只需要将这个令牌通过类的静态成员【tl】暴露给所有的类,那么就可以在任意类中通过这个令牌到各自线程的仓库中取出各自的数据。如此便实现了数据的线程绑定。

其他

一、这里使用的是静态成员实现所有类都可以访问,在Spring中容器中的bean也是唯一的,可以注入到任意类中的;所以也可以将此工具类作为一个bean放到容器中,实现相同的效果。

二、ThreadLocal除了get set 还有两个方法,也比较重要:

protected T initialValue() 可见它是一个protected方法,那用法自然是重写此方法:

private static ThreadLocal<MyData> tl = new ThreadLocal<>(){
    @Override
    protected MyData initialValue() {
        return new MyData();
    }
};

作用l:在第一次调用get时,如果如果得到的值还是null,就会调用此方法,将返回值进行set并返回。也就是初始化的作用。

ThreadLocal.withInitial(()->{return xxx;}); 作用效果与上例继承重写initialValue()一样,只不过他是一个静态方法,用起来更顺手,还可以使用函数引用优化。如下:

@Component
public class BindUtils {
    private ThreadLocal<MyData> tl = ThreadLocal.withInitial(MyData::new);

    public MyData getMyData() {
        return tl.get();
    }
}

以上就是关于ThreadLocal实现线程绑定相关的全部内容,希望对你有帮助。欢迎继续关注潘子夜个人博客,学习愉快哦!

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/10141.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号