Java并发编程之threadLocal

 更新时间:2021年09月29日 08:51:59   作者:黑夜中的小迷途  
ThreadLocal是JDK包提供的,它提供了线程本地变量,也就是说如果创建了一个ThreadLocal变量,需要的朋友可以参考一下哟

1、ThreadLocal介绍

多个线程访问同一个共享变量时特别容易出现并发问题,特别是多线程需要对共享变量进行写入时。为了保证线程安全,一般使用者在访问共享变量的时候需要进行适当的同步,如图

同步的一般措施是加锁,这就需要使用者对锁有一定的了解,这显然加重了使用者的负担,那么有没有一种方法可以做到,当创建一个变量后,每个线程对其进行访问的时候访问的是自己线程的变量呢?其实ThreadLocal就可以做到。

ThreadLocalJDK包提供的,它提供了线程本地变量,也就是说如果创建了一个ThreadLocal变量,那么访问这个变量的每一个线程都会有这个变量的一个本地副本。当多线程操作这个变量的时候,实际操作的就是自己本地内存的里面的里面的变量,从而避免了线程安全问题。创建一个ThreadLocal变量后,每一个线程都会复制一个变量到自己的本地内存。

2、ThreadLocal使用实例

package com.heiye.learn1;

public class ThreadLocalTest {
    //print方法
    static void print(String threadName) {
        //打印当前线程本地内存中LocalVariable变量的值
        System.out.println(threadName + ":" + localVariable.get());
        //清除当前线程本地内存中的localVariable变量值
        //localVariable.remove();
    }

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

    public static void main(String[] args) {
        //创建线程threadOne
        Thread threadOne = new Thread(new Runnable() {
            @Override
            public void run() {
                //设置线程one变量localVariable值
                localVariable.set("threadOne local Variable");
                //调用打印函数
                print("threadOne");
                //打印本地变量值
                System.out.println("threadOne remove after" + ":" + localVariable.get());
            }
        });
        //创建线程threadTwo
        Thread threadTwo = new Thread(new Runnable() {
            @Override
            public void run() {
                //设置线程two变量localVariable值
                localVariable.set("threadTwo local Variable");
                //调用打印函数
                print("threadTwo");
                //打印本地变量值
                System.out.println("threadTwo remove after" + ":" + localVariable.get());
            }
        });

        threadOne.start();
        threadTwo.start();
    }
}

线程one首先通过set()方法为threadLocal变量设置了一个值,这其实设置的就是线程one本地内存中对于threadLocal变量的一个副本。这个副本是线程two访问不了的。

如果清除当前线程本地内存中的localVariable变量值,也就是执行localVariable.remove() ;则:

3、ThreadLocal实现原理

首先查看一下ThreadLocal类图结构

由该图可知,Thread类有一个ThreadLocalsinheritableThreadLocals,它们都是ThreadLocalMap类型的变量,而ThreadLocalMap是一个定制化的HashMap。在默认的情况下,每个线程中的两个变量都为null,只有当第一个线程调用ThreadLocal的set或者get方法时才会创建它们,其实每个线程得到本地变量不是存放在ThreadLocal实例里面,而是存放在具体的线程内存空间里。ThreadLocal就是一个工具壳,它通过set方法把value值存放在调用线程的threadlocals里面并存放起来,当调用线程调用它的get()方法的时候,再从当前线程的threadLocals变量里面将其拿出来使用。

分析setgetremove逻辑

 //set
 public void set(T value) {
        //获取当前线程
        Thread t = Thread.currentThread();
        //将当前线程作为key,到ThreadLocalMap取查找对应的线程变量
        ThreadLocalMap map = getMap(t);
        //如果找到,则设置
        if (map != null)
            map.set(this, value);
        else //第一次调用就创建当前线程所在的hashmap
            createMap(t, value);
    }

 //get
 public T get() {
        Thread t = Thread.currentThread();
        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();
    }

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

在每一个线程内都有一个名为threadLocals的成员变量,该变量的类型为HashMap,其中的key为我们定义的threadLocal变量的this引用,value为我们使用set方法设置的值。每个线程的本地变量存放在自己的内存变量ThreadLocals中,如果当前线程一直不消亡,那么这些本地变量会一直存在,所有可能造成内存溢出。

到此这篇关于Java并发编程 threadLocal 的文章就介绍到这了,更多相关threadLocal 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于Spring统一异常处理及说明

    关于Spring统一异常处理及说明

    这篇文章主要介绍了关于Spring统一异常处理及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • Java遍历起止日期中间的所有日期操作

    Java遍历起止日期中间的所有日期操作

    这篇文章主要介绍了Java遍历起止日期中间的所有日期操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • 彻底搞懂Java多线程(四)

    彻底搞懂Java多线程(四)

    这篇文章主要给大家介绍了关于Java面试题之多线程和高并发的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2021-07-07
  • Java多维数组和Arrays类方法总结详解

    Java多维数组和Arrays类方法总结详解

    这篇文章主要介绍了Java多维数组和Arrays类方法总结详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • SpringBoot项目配置明文密码泄露问题的处理方式

    SpringBoot项目配置明文密码泄露问题的处理方式

    这篇文章主要介绍了SpringBoot项目配置明文密码泄露问题的处理方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • Springboot实现Java阿里短信发送代码实例

    Springboot实现Java阿里短信发送代码实例

    这篇文章主要介绍了springboot实现Java阿里短信发送代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Java中双重检查锁(double checked locking)的正确实现

    Java中双重检查锁(double checked locking)的正确实现

    双重检查锁(Double-Check Locking),顾名思义,通过两次检查,并基于加锁机制,实现某个功能,下面这篇文章主要给大家介绍了关于Java中双重检查锁(double checked locking)的相关资料,需要的朋友可以参考下
    2021-09-09
  • Java阻塞延迟队列DelayQueue原理及使用详解

    Java阻塞延迟队列DelayQueue原理及使用详解

    这篇文章主要介绍了Java阻塞延迟队列DelayQueue原理及使用详解,阻塞队列是一个支持两个附加操作的队列,这两个附加的操作是:在队列为空时,从队列中获取元素的消费者线程会一直等待直到队列变为非空,需要的朋友可以参考下
    2023-12-12
  • IntelliJ IDEA弹出“IntelliJ IDEA License Activation”的处理方法

    IntelliJ IDEA弹出“IntelliJ IDEA License Activation”的处理方法

    这篇文章主要介绍了IntelliJ IDEA弹出“IntelliJ IDEA License Activation”的处理方法,本文给出解决方法,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • java语言基础之标识符和命名规则详解

    java语言基础之标识符和命名规则详解

    这篇文章主要给大家介绍了关于java语言基础之标识符和命名规则的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03

最新评论