浅谈ThreadLocal

目录

一、ThreadLocal原理

二、TheadLocal特性

二、TheadLocal使用场景


一、ThreadLocal原理

1、每个Thread对象都含有一个ThreadLocalMap,ThreadLocalMap是由Entry对象构成,Entry继承自weakReference<ThreadLocal<?>>,一个Entry由ThreadLocal对象和Object构成。由此可见,Entry的key是ThreadLocal对象,并且是一个弱引用,当没指向key的强引用后,该key就会被垃圾回收器回收;

2、当执行set方法时,ThreadLocal首先会获取当前线程对象,然后获取当前线程的ThreadLocalMap对象,再以当前ThreadLocal对象为key,将值存储进ThreadLocaoMap对象中;

3、当执行get方法时,ThreadLocal首先会获取当前线程对象,然后获取当前线程的ThreadLocalMap对象,再以当前ThreadLocal对象为key,获取对应的value。

二、TheadLocal特性

1、ThreadLocal是Java中所提供的线程本地缓存机制,可以利用该机制将数据缓存在某个线程内部,该线程可以在任意时刻、任意方法中获取缓存的数据;(由于每一条线程均含有各自私有的ThreadLocalMap容器,这些容器互相独立互不影响,因此不会存在线程安全性问题,从而也无需使用同步机制来保证多条线程访问容器的互斥性)

2、ThreadLocal底层是通过ThreadLocalMap来实现的,每个Thread对象中都存在一个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要缓存的值;

3、如果在线程池中使用ThreadLocal会造成内存泄漏,因为ThreadLocal对象使用完后,应该要把设置的key和value也就是Entry对象进行回收,但线程池中不会回收,而线程对象是通过强引用指向ThreadLocalMap,ThreadLocalMap也是通过强引用指向Entry对象,线程不被回收,Entry对象也就不会被回收,从而出现内存泄漏。解决办法:在使用了ThreadLocal对象之后,手动调用ThreadLocal的remove方法,手动清除Entry对象。

二、TheadLocal使用场景

1、在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束;

2、线程间数据隔离;

3、进行事务操作,用于存储线程事务信息;

4、数据库连接,Session会话管理。

注:Spring框架z在事务开始时会给当前线程绑定一个Jdbc Connection,在整个事务过程都是使用该线程绑定的Connection来执行数据库操作,实现了事务的隔离性,Springk框架里面就是用的ThreadLocal来实现这种隔离。

案例:

public class Person {
    private ThreadLocal<String> name = new ThreadLocal<String>();

    public String getName() {
        return this.name.get();
    }

    public void setName(String name) {
        this.name.set(name);
    }
}

class Demo{
    public static void main(String[] args) {
        Person person = new Person();
        new Thread(new Runnable() {
            @Override
            public void run() {
                person.setName("张三");
                try {
                    Thread.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("测试1:" + person.getName());
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                person.setName("李四");
                try {
                    Thread.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("测试2:" + person.getName());
            }
        }).start();
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值