Java并发编程——ThreadLocal

       我们知道,在多线程访问同一个共享变量的情况下,为了保证不出现并发问题,我们往往需要对其进行同步操作,一般是通过加锁。那么,有没有一种方法,创建一个变量,使得每个线程对其进行访问都是访问自己线程的变量呢?ThreadLocal就可以实现这个操作。

何为ThreadLocal       

       ThreadLocal是JDK提供的,位于java.lang包中,它提供了一个线程的本地变量,当你创建了一个ThreadLocal变量,多个线程访问的都是这个变量的本地副本,对其进行操作实际上也是操作自己本地内存里面的变量,从而避免了线程安全问题。在介绍源码原理前,我们先来看一段使用ThreadLocal的代码加深理解。

public class ThreadLoaclTest {

    //ThreadLocal变量
    static ThreadLocal<String> localVariable = new ThreadLocal<>();

    public static void main(String[] args) {
        //创建线程t1,将ThreadLocal类型的localVariable变量赋值为t1-localVariable。
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                localVariable.set("t1-localVariable");
                print("t1");
            }
        });
        //创建线程t2,将ThreadLocal类型的localVariable变量赋值为t2-localVariable。
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                localVariable.set("t2-localVariable");
                print("t2");
            }
        });
        //启动线程t1,t2
        t1.start();
        t2.start();
    }

    //print函数,打印当前线程本地内存中localVariable变量的值
    public static void print(String str) {
        System.out.println(str + ":" + localVariable.get());
    }
}

运行结果如下。

t2:t2-localVariable
t1:t1-localVariable

       在上面这段代码中,我们在线程t1,t2中分别用set( )方法对ThreadLocal类型的localVariable变量进行赋值并将其打印,结果发现通过get( )函数获取的值是线程本地内存中的值。

 

ThreadLocal原理

       Thread类中有一个threadLocals和一个inheritableThreadLocals变量,他们都是ThreadLocalMap类型的变量,而ThreadLocalMap是一个定制化的HashMap,它存储的是key-value键值对。

       默认情况下线程中的这两个变量的都是null,只有当前线程第一次调用ThreadLocal的set( )方法或者get( )方法时才会去创建他们。其实每个线程的本地变量不是放在ThreadLocal实例中,而是放在调用线程的threadLocal变量中,也就是说,ThreadLocal类型的变量会放在当前线程的内存空间中。ThreadLocal就是一个工具壳,通过调用它的set( )将value值放入调用线程的threadlocals变量中存放起来,通过get( )将调用线程中的threadLocals值取出

       第一次读这段话的时候你可能半知半解,下面看一下下面的源码来理解。

1、ThreadLocal的 void set()

    public void set(T value) {
        //1、获取当前线程
        Thread t = Thread.currentThread();
        //2、将当前线程作为key去查找对应的线程变量,找到则设置。
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        //若为第一次调用则创建当前线程对应的threadLocals
        else
            createMap(t, value);
    }
    
   
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

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

2、ThreadLocal的 T get( )

    public T get() {
        //获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程的threadLocals变量,它是ThreadLocalMap类型的
        ThreadLocalMap map = getMap(t);
        //如果不为空,返回它的值
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //为空的话则进行初始化
        return setInitialValue();
    }

 

总结

       在每个线程内部都有一个名为threadLocals的成员变量,该变量的类型为HashMap,其中key为我们定义的ThreadLocal变量的this引用,value则为我们使用set方法设置的值。我们通过ThreadLocal这个“外壳”对其进行操作,每个线程的本地变量我们可以存放在线程自己的threadLocals中,如果当前线程不消亡,这些本地变量就会一直存在,我们可以使用ThreadLocal的remove( )方法删除。


以上即是我对ThreadLocal的理解,是在学习了《Java并发编程之美》之后所作的学习笔记,本书内容充实且易懂,十分值得一读。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值