ThreadLocal的原理与使用

一、ThreadLocal的理解
1、ThreadLocal即线程本地变量或者说是线程本地存储,ThreadLocal为中的变量在每个线程中都创建一个副本,那么每个线程可以访问自己内部的副本变量。
2、因为ThreadLocal为每个线程中的变量都创建了一个副本,即每个线程中都会有该变量,且线程内部任何地方都可以使用,线程之间互不影响,这样就不会存在线程安全。
但是,使用ThreadLocal会产生大量的副本,所以会比不使用ThreadLocal占用更多的内存资源。
二、深入理解ThreadLocal类
1、了解ThreadLocal的方法

(1) public T get(){}
(2) public void set(T value){}
(3) public void remove(){}
(4) protected T initialValue() {}

get()方法是获取变量副本,set(T value)是设置变量副本,remove()是移除变量副本,initialValue()是protected方法,一般在使用时用来重写。
2、ThreadLocal是如何创建变量副本的

 public T get() {
         //获取当前线程
        Thread t = Thread.currentThread();
        //获取ThreadLocalMap类型的map,t为当前线程
        ThreadLocalMap map = getMap(t);
        //获取key,value键值对(参数是this,而不是当前线程)
        //如果获取成功,则返回value值
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //如果获取不成功,返回setInitialValue();
        return setInitialValue();
    }
 //getMap(Thread t)方法
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
 }

在getMap(Thread t)方法中,返回的是一个线程的成员变量。

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;
}

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

首先:在每个Thread内部会有一个ThreadLocal.ThreadLocalMap的成员变量threadLocals,threadLocals就是用来存储每一个变量副本的,键为当前的ThreadLocal变量,value为每一个变量副本(T类型);
初始时,ThreadLocals为空,当通过get(),set()方法就会对ThreadLocals进行初始化,并且以当前ThreadLocal为key值,以ThreadLocal要保存的变量副本为value,存到ThreadLocals中。
然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找。
下面为通过ThreadLocal创建的变量副本的例子

public class TestThreadLocal {
    ThreadLocal<Long> longThreadLocal = new ThreadLocal<>();
    ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();


    public void  set(){
        longThreadLocal.set(Thread.currentThread().getId());
        stringThreadLocal.set(Thread.currentThread().getName());
    }

    public Long getLongThreadLocal() {
        return longThreadLocal.get();
    }

    public void setLongThreadLocal(ThreadLocal<Long> longThreadLocal) {
        this.longThreadLocal = longThreadLocal;
    }

    public String getStringThreadLocal() {
        return stringThreadLocal.get();
    }
    public void setStringThreadLocal(ThreadLocal<String> stringThreadLocal) {
        this.stringThreadLocal = stringThreadLocal;
    }
    public static void main(String[] args) throws InterruptedException {
        TestThreadLocal threadLocal = new TestThreadLocal();
        threadLocal.set();
        System.out.println(threadLocal.getLongThreadLocal());
        System.out.println(threadLocal.getStringThreadLocal());
        Thread thread = new Thread(){
            @Override
            public void run() {
                threadLocal.set();
                System.out.println(threadLocal.getLongThreadLocal());
                System.out.println(threadLocal.getStringThreadLocal());
            }
        };
        thread.start();
        thread.join();
        System.out.println(threadLocal.getLongThreadLocal());
        System.out.println(threadLocal.getStringThreadLocal());
    }
}

输出结果:
这里写图片描述

三、应用场景
最常见的ThreadLocal使用场景为 用来解决 数据库连接、Session管理等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值