文档章节

ThreadLocal原理分析

AaronSheng
 AaronSheng
发布于 2017/07/29 18:09
字数 571
阅读 16
收藏 1

ThreadLocal 为了解决多线程并发提供了一种新的思路,ThreadLocal 为每个变量维护一个线程的副本,每个线程可以独立的修改副本,不会影响到其他线程。使用 ThreadLocal 可能需要注意引用的释放,如果忘记释放可能会导致对象释放不了。

ThreadLocal 写数据过程:

  1. 从 ThreadLocal 的 set 方法中我们可以看到, ThreadLocal 首先获取到了当前线程, 并获取到 Thread 的 threadLocals 变量;
  2. 拿到 threadLocals 后,通过这个 ThreadLocalMap 使用 ThreadLocal 对象作为键,拿到相应的数据,因为 threadLocals 是属于当前线程的,只有当前线程才能拿到该对象,所以没有并发问题。


ThreadLocal 读数据过程:

  1. 从 ThreadLocal 的 get 方法中我们可以看到, ThreadLocal 首先获取到了当前线程, 并获取到 Thread 的 threadLocals 变量;
  2. 拿到 threadLocals 后,如果 threadLocals 为空,则使用数据创建一个 ThreadLocalMap 对象,并赋值给当前线程的 threadLocals 变量;如果不为空,则直接使用 threadLocals 设置数据,因为 threadLocals 是属于当前线程的,只有当前线程才能拿到该对象,所以写同样并发问题。

      总的来说,ThreadLocal 将数据存储在当前线程的 Thread.threadLocals 这个 ThreadLocalMap 中,而且只有当前线程才能获得这个变量,所以 ThreadLocal 不存在并发问题。

ThreadLocal 结构:

public class ThreadLocal<T> {
    private final int threadLocalHashCode = nextHashCode();
    private static AtomicInteger nextHashCode = new AtomicInteger();
    private static final int HASH_INCREMENT = 1640531527;

    public T get() {
        // 获取当前线程,并拿到 threadLocals
        Thread var1 = Thread.currentThread();
        ThreadLocal.ThreadLocalMap var2 = this.getMap(var1);
        if(var2 != null) {
            // 通过 this 拿到存在当前线程 threadLocals 中的对象
            ThreadLocal.ThreadLocalMap.Entry var3 = var2.getEntry(this);
            if(var3 != null) {
                Object var4 = var3.value;
                return var4;
            }
        }

        return this.setInitialValue();
    }

    private T setInitialValue() {
        Object var1 = this.initialValue();
        Thread var2 = Thread.currentThread();
        ThreadLocal.ThreadLocalMap var3 = this.getMap(var2);
        if(var3 != null) {
            var3.set(this, var1);
        } else {
            this.createMap(var2, var1);
        }

        return var1;
    }

    public void set(T var1) {
        // 获取当前线程,并拿到 threadLocals
        Thread var2 = Thread.currentThread();
        ThreadLocal.ThreadLocalMap var3 = this.getMap(var2);
        if(var3 != null) {
            // 如果 map 不为空,通过 this 将对象存到当前线程 threadLocals 中
            var3.set(this, var1);
        } else {
            // 如果 map 为空,则创建新的 map,并将对象存到 threadLocals 中
            this.createMap(var2, var1);
        }

    }

    public void remove() {
        ThreadLocal.ThreadLocalMap var1 = this.getMap(Thread.currentThread());
        if(var1 != null) {
            var1.remove(this);
        }
    }

    // 获取线程的 threadLocals 变量
    ThreadLocal.ThreadLocalMap getMap(Thread var1) {
        return var1.threadLocals;
    }

    void createMap(Thread var1, T var2) {
        var1.threadLocals = new ThreadLocal.ThreadLocalMap(this, var2);
    }
}

 

© 著作权归作者所有

上一篇: protobuf
AaronSheng
粉丝 14
博文 52
码字总数 51122
作品 0
深圳
程序员
私信 提问
PerfMa给OpenJDK社区提交的第一个Patch

概述 前两天给openjdk gc-dev的email list提交了一个问题,主要是针对Full GC之后,GC日志里Metaspace的大小在GC前后都一直不变的问题,我在邮件里大概也提了下如何修复该问题,以及猜测了下...

你假笨
2018/09/25
0
0
Java 线程本地 ThreadLocal 的分析和总结

ThreadLocal类在Spring,Hibernate等框架中起到了很大的作用,对于其工作原理,很多网上的文章分析的不够彻底,甚至有些误解。 首先,为了解释ThreadLocal类的工作原理,必须同时介绍与其工作...

绿悠悠
2010/10/07
2.8K
0
ThreadLocal源码分析

阅读原文请访问我的博客 BrightLoong's Blog 一. 简介 提醒篇幅较大需耐心。 简介来自ThreadLocal类注释 ThreadLocal类提供了线程局部 (thread-local) 变量。这些变量与普通变量不同,每个线...

BrightLoong
2018/05/28
0
0
升级到JDK9的一个BUG,你了解吗

概述 前几天在一个群里看到一个朋友发了一个demo,说是JDK的bug,昨天在JVM的一个群里又有朋友发了,觉得挺有意思,分享给大家,希望大家升级JDK的版本的时候注意下是否存在这样的代码,如果...

你假笨
2018/06/06
0
0
Java NIO原理 图文分析及代码实现

Java NIO原理图文分析及代码实现 前言: 最近在分析hadoop的RPC(Remote Procedure Call Protocol ,远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术...

囚兔
2015/04/29
281
1

没有更多内容

加载失败,请刷新页面

加载更多

《Designing.Data-Intensive.Applications》笔记 四

第九章 一致性与共识 分布式系统最重要的的抽象之一是共识(consensus):让所有的节点对某件事达成一致。 最终一致性(eventual consistency)只提供较弱的保证,需要探索更高的一致性保证(stro...

丰田破产标志
今天
6
0
docker 使用mysql

1, 进入容器 比如 myslq1 里面进行操作 docker exec -it mysql1 /bin/bash 2. 退出 容器 交互: exit 3. mysql 启动在容器里面,并且 可以本地连接mysql docker run --name mysql1 --env MY...

之渊
今天
7
0
python数据结构

1、字符串及其方法(案例来自Python-100-Days) def main(): str1 = 'hello, world!' # 通过len函数计算字符串的长度 print(len(str1)) # 13 # 获得字符串首字母大写的...

huijue
今天
5
0
OSChina 周日乱弹 —— 我,小小编辑,食人族酋长

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @宇辰OSC :分享娃娃的单曲《飘洋过海来看你》: #今日歌曲推荐# 《飘洋过海来看你》- 娃娃 手机党少年们想听歌,请使劲儿戳(这里) @宇辰OSC...

小小编辑
今天
1K
11
MongoDB系列-- SpringBoot 中对 MongoDB 的 基本操作

SpringBoot 中对 MongoDB 的 基本操作 Database 库的创建 首先 在MongoDB 操作客户端 Robo 3T 中 创建数据库: 增加用户User: 创建 Collections 集合(类似mysql 中的 表): 后面我们大部分都...

TcWong
今天
40
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部