揭秘“ThreadLocal"

7 篇文章 0 订阅

引导语

ThreadLocal也是线程安全的一种措施,有这么一个经典的比喻“人手一只笔”,如果有100个人要签名,只有一支笔的话,那么肯定要排起长队了,但如果准备了100支笔,那就可以做到每人一支笔啦。

ThreadLocal的官方解释:线程局部变量,是一个以ThreadLocal对象为键,任意对象为值得存储结构,这个结构倍附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询绑定在这个线程上的一个值。(Java并发编程的艺术,P105)

让我们结合源码和示例,来理解ThreadLocal吧!

 

一、ThreadLocal源码

在Java.lang包下

1、构造方法:只有一个无参构造

public ThreadLocal() {}

2、常用方法:set()

    public void set(T value) {
        Thread t = Thread.currentThread(); //获得当前线程
        ThreadLocalMap map = getMap(t);    //获得ThreadLocalMap 
        if (map != null)
            map.set(this, value);          //map的常规赋值操作
        else
            createMap(t, value);
    }
  • 紧接着,我们看这个getMap()方法做了什么
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;  //根据当前线程,从当前线程中取出ThreadLocalMap
    }
  • 原来存储着各种变量的map在Thread中!让我们来到Thread类的源码中看看:
    ThreadLocal.ThreadLocalMap threadLocals = null;
  • 回到ThreadLocal源码,再看看createMap()做了什么:
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
  • 总结:set方法调用时,首先获取当前线程,再从当前线程中获取ThreadLocalMap,如果这个map不为空,则set值,如果这个map是空的,则在当前线程创建ThreadLocalMap,然后再set。
  • 注意:ThreadLocalMap是属于线程的,这个map的key是ThreadLocal对象,value就是它在当前线程中的取值。
  • 上图:图片来自网络,侵删,谢谢!

3、常用方法:get()

    public T get() {
        Thread t = Thread.currentThread();  //先得到当前线程
        ThreadLocalMap map = getMap(t);     //取出当前线程中的ThreadLocalMap 
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this); 
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

 

三、使用示例

  • ThreadLocal一般定义成静态成员变量,以供使用

1、实现了Runnable接口的类

class ThreadLocalTest implements Runnable{
    static ThreadLocal<String> str=new ThreadLocal<String>(){
        @Override
        protected String initialValue() {
            return Thread.currentThread().getName();  //设置初始值为线程名
        }
    };

    @Override
    public void run(){
        try {
            //打印出当前线程名,ThreadLocal对象str在当前线程中的值
            System.out.println(Thread.currentThread().getName()+":"+str.get());
            Thread.sleep(10);
        }catch (Exception e){
            System.out.println(e);
        }
    }
}

2、主方法

    public class TryThreadLocal {
        public static void main(String[] args){
            Thread t1=new Thread(new ThreadLocalTest());
            Thread t2=new Thread(new ThreadLocalTest());
            t1.start();
            t2.start();
        }
    }

3、运行结果

 

三、应用场景

1、用在数据库连接中,用threadlocal保存Connection对象,可以保证在线程各处的数据库连接都是相同的,而且各个请求之间不影响。

2、用在session管理中,可以保证每个请求的会话不会相互影响。

3、线程上下文相关的信息,例如用户ID、交易ID等等。

 

 

感谢:

https://my.oschina.net/davidzhang/blog/111010

https://droidyue.com/blog/2016/03/13/learning-threadlocal-in-java/

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值