服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java并发编程之threadLocal

Java并发编程之threadLocal

2022-01-22 16:36黑夜中的小迷途 Java教程

ThreadLocal是JDK包提供的,它提供了线程本地变量,也就是说如果创建了一个ThreadLocal变量,需要的朋友可以参考一下哟

1、ThreadLocal介绍

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

Java并发编程之threadLocal

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

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

Java并发编程之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();
  }
}

Java并发编程之threadLocal

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

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

Java并发编程之threadLocal

 

3、ThreadLocal实现原理

首先查看一下ThreadLocal类图结构

Java并发编程之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 内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/xiaomitu/p/15349149.html

延伸 · 阅读

精彩推荐
  • Java教程Java中StringUtils工具类的一些用法实例

    Java中StringUtils工具类的一些用法实例

    这篇文章主要介绍了Java中StringUtils工具类的一些用法实例,本文着重讲解了isEmpty和isBlank方法的使用,另外也讲解了trim、strip等方法的使用实例,需要的朋友可...

    junjie3762019-12-20
  • Java教程Java常见内存溢出异常分析与解决

    Java常见内存溢出异常分析与解决

    本篇文章主要分析了JAVA程序内存溢出问题原因,较为详细的说明了java导致程序内存溢出的原因与解决方法,感兴趣的小伙伴们可以参考一下。...

    馨桑移梦4852020-06-24
  • Java教程解读@RequestBody的正确使用方法

    解读@RequestBody的正确使用方法

    这篇文章主要介绍了解读@RequestBody的正确使用方法,具有一定借鉴价值...

    li9546443519352021-03-22
  • Java教程java回溯算法解数独问题

    java回溯算法解数独问题

    这篇文章主要为大家详细介绍了java回溯算法解数独问题,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    天涯泪小武10042021-07-10
  • Java教程Java通用Mapper UUID简单示例

    Java通用Mapper UUID简单示例

    今天小编就为大家分享一篇关于Java通用Mapper UUID简单示例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看...

    isea5335352021-06-24
  • Java教程java排序高级之选择排序实现方法

    java排序高级之选择排序实现方法

    这篇文章主要介绍了java排序高级之选择排序实现方法,较为全面的分析了选择排序的原理与具体实现技巧,非常具有实用价值,需要的朋友可以参考下 ...

    Benjamin_whx3552019-12-10
  • Java教程Java 中HttpURLConnection附件上传的实例详解

    Java 中HttpURLConnection附件上传的实例详解

    这篇文章主要介绍了Java 中HttpURLConnection附件上传的实例详解的相关资料,希望通过本文大家能掌握这样的知识内容,需要的朋友可以参考下...

    xiaobojava10002021-01-04
  • Java教程如何获得spring代理对象的原对象

    如何获得spring代理对象的原对象

    这篇文章主要介绍了如何获得spring代理对象的原对象的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    单曲TI10082021-10-16