一、ThreadLocal简介

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

同步一般是通过加锁来实现的,但这对用户有一定要求,加重了使用者的负担.使用ThredLocal就可以做到,创建一个变量后,每个线程对其访问的时候访问的是自己创建的变量.

如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会拥有一个这个变量的副本.操作的时候也是操作的属于自己这个线程的变量,从而避免了线程安全问题.


二、ThreadLocal使用示例

package ThreadLocalTest;public class ThreadLocalTest {static void print(String str) {//1.1 打印当前线程本地内存中localVariable变量的值System.out.println(str + ":" + localVariable.get());//清除当前线程本地内存中的localVariable的值//localVariable.remove();}//    创建ThreadLocal变量static ThreadLocal<String> localVariable = new ThreadLocal<String>();//    创建线程onepublic static void main(String[] args) {Thread threadOne = new Thread(new Runnable() {@Overridepublic void run() {//                设置线程One中本地变量loalVariable的值localVariable.set("threadOne local variable");
//                调用打印函数print("threadOne");
//                打印本地变量值System.out.println("threadOne remove after" + ":" + localVariable.get());}});
//        创建线程twoThread threadTwo = new Thread(new Runnable() {@Overridepublic void run() {//                设置线程Two中本地变量loalVariable的值localVariable.set("threadTwo local variable");
//                调用打印函数print("threadTwo");
//                打印本地变量值System.out.println("threadTwo remove after" + ":" + localVariable.get());}});
//        启动线程threadOne.start();threadTwo.start();}
}

运行结果如下

threadOne:threadOne local variable
threadOne remove after:threadOne local variable
threadTwo:threadTwo local variable
threadTwo remove after:threadTwo local variable

线程One中的代码3.1通过set方法设置了localVariable的值,这其实设置的是线程One本地内存中的一个副本,这个副本线程Two是访问不了的。然后代码3.2调用了print函数,代码1.1通过get函数获取了当前线程(线程One)本地内存中localVariable的值。

线程Two的执行类似于线程One。

将localVariable.remove 这一句代码的注释删除

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

运行结果如下所示:

threadOne:threadOne local variable
threadOne remove after:null
threadTwo:threadTwo local variable
threadTwo remove after:null

三、ThreadLocal实现原理

首先看一下ThreadLocal相关类的类图结构

由该图可知,Thread类中有一个threadLocals和一个inheritableThreadLocals,它们都是ThreadLocalMap类型的变量.而ThreadLocalMap是一个定制化的Hashmap。在默认情况下,每个线程中的这两个变量都为null,只有当前线程第一次调用ThreadLocal的set或者get方法时才会创建它们。其实每个线程的本地变量不是存放在ThreadLocal实例里面,而是存放在调用线程的threadLocals变量里面。

也就是说,ThreadLocal类型的本地变量存放在具体的线程内存空间中。ThreadLocal就是一个工具壳,它通过set方法把value值放入调用线程的threadLocals里面并存放起来,当调用线程调用它的get方法时,再从当前线程的threadLocals变量里面将其拿出来使用

如果调用线程一直不终止,那么这个本地变量会一直存放在调用线程的threadLocals变量里面,所以当不需要使用本地变量时可以通过调用ThreadLocal变量的remove方法,从当前线程的threadLocals里面删除该本地变量。另外,Thread里面的threadLocals为何被设计为map结构?很明显是因为每个线程可以关联多个ThreadLocal变量。

java多线程之ThreadLoal详解相关推荐

  1. Java多线程之volatile详解

    Java多线程之volatile详解 目录: 什么是volatile? JMM内存模型之可见性 volatile三大特性之一:保证可见性 volatile三大特性之二:不保证原子性 volatile三 ...

  2. Java多线程之Synchronized详解

    一直以来对于Synchronized都比较迷惑,尤其还对于ReentrantLock并不了解他们之间的区别,今天闲来无事,学习了. 1,为什么要使用Synchronized 首先看Synchroniz ...

  3. 多线程之callable详解

    多线程之callable详解 面试有人会问:线程的实现方式有几种? 很多人可能回答:2种,继承Thread类,实现Runnable接口. 很多忽略了callable这种方式. 也许有人知道callab ...

  4. Java并发编程之CyclicBarrier详解

    简介 栅栏类似于闭锁,它能阻塞一组线程直到某个事件的发生.栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行.闭锁用于等待事件,而栅栏用于等待其他线程. CyclicBarrier ...

  5. Java并发编程之ConcurrentLinkedQueue详解

    简介 在并发编程中我们有时候需要使用线程安全的队列.如果我们要实现一个线程安全的队列有两种实现方式一种是使用阻塞算法,另一种是使用非阻塞算法.使用阻塞算法的队列可以用一个锁(入队和出队用同一把锁)或两 ...

  6. Java并发编程之AQS详解

    一.概述 谈到并发,不得不谈ReentrantLock:而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)! 类如其名,抽象的队列式的同步器,AQ ...

  7. 多线程之ThreadPoolExecutor详解

    一.为什么使用ThreadPoolExecutor来创建线程池 线程资源必须通过线程池提供,不允许在应用中自行显式创建线程. 因为线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解 ...

  8. 异步多线程之ThreadPool详解

    上一篇:异步多线程之Thread 下一篇:异步多线程之入Task 介绍 ThreadPool 是 .net 2.0 时代的产物,有了 Thread 为什么还会有 ThreadPool 呢?Thread ...

  9. java并发编程之Volatile详解

    前言 在Java中多个线程对公共变量的操作并不是直接在内存中操作的,每一个线程都会有一块自己的工作内存.线程会先从主内存中获取到变量的值到工作内存中进行修改在更新到主内存.假如有两个线程同时对某个变量 ...

最新文章

  1. Python赋值运算符(入门必读)
  2. python把坐标写入文本_Python实现将数据写入netCDF4中的方法示例
  3. 大话WiFi省电模式
  4. AAAI 2020 | NAS+目标检测:AI设计的目标检测模型长啥样?
  5. php定位符,行定位符、单词定界符实例用法(正则表达式字符集1)
  6. sql 一次性批量插入_考虑使用SQL批量插入的安全性
  7. centos6.0的gnome桌面的一个大bug
  8. IDEA导入jar包之后引用不了
  9. MATLAB 符号函数变量替换为常量
  10. go php 框架,go框架 - Go语言中文网 - Golang中文社区
  11. AIX 修 炼 之 路
  12. 说明文中国第一台亮子计算机揭秘,2018届九年级语文中考复习(河南)课件:第2部分 第二讲 说明文阅读 2017名题强化训练.ppt...
  13. 用Eclipse开发Java语言程序,32单片机,51单片机和C语言程序(全部使用开源软件)
  14. 西伯利亚入夏火灾频发 中俄白桦茸企业启动原料保障计划
  15. MSP430F149用模拟SPI和FM25CL640通信
  16. Android:SQLite数据库学习小结
  17. 最小二乘法理解与应用
  18. 如何创建一个虚拟机?
  19. 【c++中内存拷贝函数(C++ memcpy)详解】
  20. EXCEl2013 创建下拉菜单

热门文章

  1. kafka maven没有下载_Kafka 系列(三)——Kafka 生产者详解
  2. html语言闪烁特效代码,css3 文字闪烁特效代码
  3. php将字符变为数字,数字字符怎么转化为数字 php 怎么将字符转成数字
  4. dw相对路径怎么改_密云ETL怎么收费
  5. python中doc=parased.getroot()_python中执行sed命令操作源文件时出现错误
  6. Castor xsd生成java_java – Castor可以处理从基础XSD导入的多个XSD生成类吗?
  7. strspn函数php,php strspn函数怎么用?
  8. 类中函数模板 typeof_Julia中的typeof()函数
  9. JENKINS使用DOCKER运行PYTEST并且出ALLURE报告
  10. 计算机组成原理和体系结构----软考(到处copy)