Java并发编程---ThreadLocal源码解析

Java并发编程---ThreadLocal源码解析

技术杂谈小彩虹2021-07-18 13:29:38100A+A-

这是我参与更文挑战的第8天,活动详情查看: 更文挑战

1、ThreadLocal是什么?

ThreadLocal和synchronized关键字都是用来保证多线程情况下的并发访问,但是ThreadLocal和synchronized关键字有本质的区别

synchronized是利用锁的机制让代码在某一个时刻只有一个线程去访问一段代码或者变量。

而ThreadLocal它是为每一个线程提供一个变量的副本,使每个线程都有一个变量的副本,每个线程都访问自己的变量副本,这就实现了所谓的线程隔离 比如Spring就用到了ThreadLocal,Spring在实现事务的时候,就用到了ThreadLocal,每个线程来保存自己的连接, 说Spring的事务可能做Android的没接触过,但是Handler 的Looper类就是利用了ThreadLocal的特性,保证每个线程只存在一个Looper对象

2、ThreadLocal的使用

public class UseThreadLocal {
    private static ThreadLocal<Integer> threadLocal=new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {//初始化变量
            return 1;
        }
    };
    public static void main(String[] args) {
        for (int i=0;i<3;i++){
            new Thread(new TestThread(i)).start();
        }
    }
    public static class TestThread implements Runnable{
        int id;
        public TestThread(int id) {
            this.id=id;
        }

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+":start");
             Integer s=  threadLocal.get();
             s=s+id;
            threadLocal.set(s);
            System.out.println(Thread.currentThread().getName()+":"+ threadLocal.get());
        }
    }
}

运行结果

image.png

看我们的运行结果,Thread0,Thread1,Thread2的输出结果分别是1,2,3,没有相互影响,达到了我们预期的效果,这三个线程分别拥有了Interger的副本

我们在看一下不用ThreadLocal的效果

   private static Integer count=new Integer(1);
    public static void main(String[] args) {
        for (int i=0;i<3;i++){
            new Thread(new TestThread(i)).start();
        }
    }
    public static class TestThread implements Runnable{
        int id;
        public TestThread(int id) {
            this.id=id;
        }

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+":start");
            count=count+id;

            System.out.println(Thread.currentThread().getName()+":"+count );
        }
    }

运行结果

image.png

运行结果就是,他们没有隔离,三个线程操作的是同一个对象,而不是对象副本

3、ThreadLocal的实现

ThreadLocal看他的实现,从哪看起呢?咱们就从threadLocal的set方法和get方法看起

get方法

image.png

我们在这个方法里可以看到什么呢?

有一个存储的Map

每次get的时候会先获取当前线程的ThreadLocalMap,我们去看一下getMap方法

image.png

threadLocals每个线程里都会有的对象

image.png

而且这个ThreadLocalMap是定义在ThreadLocal里面的 然后我们再往下看 get完map,如果为空就返回初始值,如果不为空,就返回以当前的ThreadLocal对象为Key的一个Entry对象,然后再返回Entry的value

咱们再去看看代码里的Entry

image.png

emmm 跟我说的一样,但是xdm你看一下上边的代码下边还有一个Entry数组,为什么要用数组呢?因为我们可能不仅定义一个ThreadLocal嘛,这不就说的通了

再看设置初始值的方法

image.png 他就是以当前的ThreadLocal为Key,以初始值为value存进ThradLocalMap里的Entry数组里

ThreadLocalMap 的set方法

image.png 看到这里大家应该明白它具体是怎么实现的了吧

我们再看一下 ThreadLocal的set方法

image.png

和设置初始值的方法差不太多 我们ThreadLocal在设置值的时候也就是执行set方法的时候,它会去设置每个线程对象里边的LocalMap里键为ThreadLocal的value,这样就实现了每个线程里的变量副本 看到这里大家应该知道ThreadLocal是怎么实现的了吧!如果有的xdm看到这里感觉还是脑袋瓜子嗡嗡的,咱们上图

image.png

3、总结

我们从ThreadLocal的作用和使用,和源码里是怎么实现的学习了ThreadLocal!如有错误之处请大佬们在评论区提出!希望大佬们一键三连!

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1

联系我们