Java中ThreadLocal的使用及原理详解

 更新时间:2023年09月26日 10:37:10   作者:回家放羊吧  
这篇文章主要介绍了Java中ThreadLocal的使用及原理详解,ThreadLocal是JDK提供的,提供线程本地变量,主要用来存放线程独有变量和解决参数传递问题的,需要的朋友可以参考下

简介

ThreadLocal是JDK提供的,提供线程本地变量,主要用来存放线程独有变量和解决参数传递问题的。

例子

public static void main(String[] args) {
        ThreadLocal threadLocal = new ThreadLocal();
        for(int i=0;i<3;i++){
            new Thread(()->{
                double random = Math.floor(Math.random()*10);
                threadLocal.set(random);
                System.out.println("设置线程"+Thread.currentThread().getName()+",线程变量:"+random);
                System.out.println("查看线程"+Thread.currentThread().getName()+",线程变量:"+threadLocal.get());
            }).start();
        }
    }

设置线程Thread-2,线程变量:4.0
设置线程Thread-0,线程变量:9.0
设置线程Thread-1,线程变量:5.0
查看线程Thread-0,线程变量:9.0
查看线程Thread-2,线程变量:4.0
查看线程Thread-1,线程变量:5.0

可以看出,每个线程的变量是隔离开的,避免了出现线程不安全的问题,ThreadLocal是如何实现的呢?

原理

ThreadLocalMap

 public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
 }

ThreadLocalMap是真正存储数据的地方,ThreadLocalMap在各个线程中,为线程独有的

set方法

public void set(T value) {
		//获取调用者线程
        Thread t = Thread.currentThread();
        //获取调用者线程自有的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null)
        	//如果map!=null直接设置值
            map.set(this, value);
        else
        	//创建ThreadLocalMap,并将value存储
            createMap(t, value);
    }
    ThreadLocalMap getMap(Thread t) {
    	//获取线程的ThreadLocalMap
        return t.threadLocals;
    }
    void createMap(Thread t, T firstValue) {
    	//创建ThreadLocalMap,并设置firstValue
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

从set方法中第二行代码ThreadLocalMap map = getMap(t);这段代码是获取当前线程的ThreadLocalMap,然后进行设置值,通过getMap方法可以看出,线程本地变量并不是存储在ThreadLocal,而是存储在各自线程的ThreadLocalMap threadLocals中的,ThreadLocal只是相当于一个工具类,对ThreadLocalMap进行操作而已。

get方法

public T get() {
		//获取调用者线程
        Thread t = Thread.currentThread();
        //获取调用者线程自有的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        	//获取到当前ThreadLocal的值
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    private T setInitialValue() {
    	//获取默认值(null),也可以重写该方法
        T value = initialValue();
        //获取调用者线程
        Thread t = Thread.currentThread();
        //获取调用者线程自有的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null)
        	//设置为空
            map.set(this, value);
        else
        	//创建一个ThreadLocalMap,赋值为空
            createMap(t, value);
        return value;
    }

get方法是获取当前线程的ThreadLocalMap,然后通过将ThreadLocal当做key,从ThreadLocalMap中获取到相应的Entry,Entry里包含了key和value,最后将value返回,如果没有key的值,就会调用setInitialValue方法,setInitialValue方法会初始化一个默认值,默认值是null,也可以重写initialValue,获得自己想要的默认值,如果没有创建ThreadLocalMap,则创建,然后返回默认值

remove方法

public void remove() {
	     //获取调用者线程自有的ThreadLocalMap
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             //删除ThreadLocalMap中key为当前ThreadLocal的数据
             m.remove(this);
    }

remove方法十分简单,就是删除ThreadLocalMap中key为当前ThreadLocal的数据

总结

通过看源码,可以得出

  1. ThreadLcoal只是一个用来操作ThreadLocalMap的一个工具类和充当ThreadLocalMap的key。
  2. ThreadLocalMap是真正存储数据的,但是ThreadLocalMap是存储在每个线程中的。
  3. 每个线程都有各自的ThreadLocalMap,这也是实现线程隔离的根本原因。

到此这篇关于Java中ThreadLocal的使用及原理详解的文章就介绍到这了,更多相关ThreadLocal的使用及原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot中集成串口通信的项目实践

    SpringBoot中集成串口通信的项目实践

    本文主要介绍了SpringBoot中集成串口通信,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • Nacos配置中心的配置文件的匹配规则及说明

    Nacos配置中心的配置文件的匹配规则及说明

    这篇文章主要介绍了Nacos配置中心的配置文件的匹配规则及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Java源码刨析之ArrayQueue

    Java源码刨析之ArrayQueue

    在本篇文章当中主要给大家介绍一个比较简单的JDK为我们提供的容器ArrayQueue,这个容器主要是用数组实现的一个单向队列,整体的结构相对其他容器来说就比较简单了
    2022-07-07
  • Java模拟新浪和腾讯自动登录并发送微博

    Java模拟新浪和腾讯自动登录并发送微博

    这篇文章主要为大家详细介绍了Java模拟新浪和腾讯自动登录并发送微博功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • Java检查字符串是否一致的四种方法

    Java检查字符串是否一致的四种方法

    字符串比较是常见的操作,包括比较相等、比较大小、比较前缀和后缀串等,在 Java 中,比较字符串的常用方法有四个:equals(),equalsIgnoreCase(),compareTo()和compareToIgnoreCase(),下面详细介绍这四个方法的使用
    2024-04-04
  • 关于easyExcel中读取Excel表头的实例说明

    关于easyExcel中读取Excel表头的实例说明

    EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称,下面这篇文章主要给大家介绍了关于easyExcel中读取Excel表头的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • SpringBoot使用WebSocket实现向前端推送消息功能

    SpringBoot使用WebSocket实现向前端推送消息功能

    WebSocket协议是基于TCP的一种新的网络协议,它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端,本文给大家介绍了SpringBoot使用WebSocket实现向前端推送消息功能,需要的朋友可以参考下
    2024-05-05
  • 32位和64位皆适用的MyEclipse安装教程

    32位和64位皆适用的MyEclipse安装教程

    这篇文章主要为大家详细介绍了32位和64位皆适用的MyEclipse安装教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • springboot与vue详解实现短信发送流程

    springboot与vue详解实现短信发送流程

    随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容
    2022-06-06
  • SpringCloud实现灰度发布的方法步骤

    SpringCloud实现灰度发布的方法步骤

    本文主要介绍了SpringCloud实现灰度发布的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05

最新评论