一、用法

ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。

1、ThreadLocal.get: 获取ThreadLocal中当前线程共享变量的值。

2、ThreadLocal.set: 设置ThreadLocal中当前线程共享变量的值。

3、ThreadLocal.remove: 移除ThreadLocal中当前线程共享变量的值。

4、ThreadLocal.initialValue: ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值。

package com.coshaho.reflect;/*** ThreadLocal用法* @author coshaho**/
public class MyThreadLocal
{private static final ThreadLocal<Object> threadLocal = new ThreadLocal<Object>(){/*** ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值*/@Overrideprotected Object initialValue(){System.out.println("调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!");return null;}};public static void main(String[] args){new Thread(new MyIntegerTask("IntegerTask1")).start();new Thread(new MyStringTask("StringTask1")).start();new Thread(new MyIntegerTask("IntegerTask2")).start();new Thread(new MyStringTask("StringTask2")).start();}public static class MyIntegerTask implements Runnable{private String name;MyIntegerTask(String name){this.name = name;}@Overridepublic void run() {for(int i = 0; i < 5; i++){// ThreadLocal.get方法获取线程变量if(null == MyThreadLocal.threadLocal.get()){// ThreadLocal.et方法设置线程变量MyThreadLocal.threadLocal.set(0);System.out.println("线程" + name + ": 0");}else{int num = (Integer)MyThreadLocal.threadLocal.get();MyThreadLocal.threadLocal.set(num + 1);System.out.println("线程" + name + ": " + MyThreadLocal.threadLocal.get());if(i == 3){MyThreadLocal.threadLocal.remove();}}try{Thread.sleep(1000);}catch (InterruptedException e){e.printStackTrace();}}   }}public static class MyStringTask implements Runnable{private String name;MyStringTask(String name){this.name = name;}@Overridepublic void run() {for(int i = 0; i < 5; i++){if(null == MyThreadLocal.threadLocal.get()){MyThreadLocal.threadLocal.set("a");System.out.println("线程" + name + ": a");}else{String str = (String)MyThreadLocal.threadLocal.get();MyThreadLocal.threadLocal.set(str + "a");System.out.println("线程" + name + ": " + MyThreadLocal.threadLocal.get());}try{Thread.sleep(800);}catch (InterruptedException e){e.printStackTrace();}}}}
<strong>}
</strong>

运行结果如下:

调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
线程IntegerTask1: 0
调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
线程IntegerTask2: 0
调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
线程StringTask1: a
线程StringTask2: a
线程StringTask1: aa
线程StringTask2: aa
线程IntegerTask1: 1
线程IntegerTask2: 1
线程StringTask1: aaa
线程StringTask2: aaa
线程IntegerTask2: 2
线程IntegerTask1: 2
线程StringTask2: aaaa
线程StringTask1: aaaa
线程IntegerTask2: 3
线程IntegerTask1: 3
线程StringTask1: aaaaa
线程StringTask2: aaaaa
调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
线程IntegerTask2: 0
调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
线程IntegerTask1: 0

大家可以点击加群【JAVA架构知识学习讨论群】473984645,(如多你想跳槽换工作,但是技术又不够,或者工作遇到了瓶颈,我这里有一个Java的免费直播课程,讲的是高端的知识点,只要有1-5年的开发工作经验可以加群找我要课堂链接。)注意:是免费的 没有开发经验的误入。

二、原理

线程共享变量缓存如下:

Thread.ThreadLocalMap<ThreadLocal, Object>;

1、Thread: 当前线程,可以通过Thread.currentThread()获取。

2、ThreadLocal:我们的static ThreadLocal变量。

3、Object: 当前线程共享变量。

我们调用ThreadLocal.get方法时,实际上是从当前线程中获取ThreadLocalMap<ThreadLocal, Object>,然后根据当前ThreadLocal获取当前线程共享变量Object。

ThreadLocal.set,ThreadLocal.remove实际上是同样的道理。

这种存储结构的好处:

1、线程死去的时候,线程共享变量ThreadLocalMap则销毁。

2、ThreadLocalMap<ThreadLocal,Object>键值对数量为ThreadLocal的数量,一般来说ThreadLocal数量很少,相比在ThreadLocal中用Map<Thread, Object>键值对存储线程共享变量(Thread数量一般来说比ThreadLocal数量多),性能提高很多。

关于ThreadLocalMap<ThreadLocal, Object>弱引用问题:

当线程没有结束,但是ThreadLocal已经被回收,则可能导致线程中存在ThreadLocalMap<null, Object>的键值对,造成内存泄露。(ThreadLocal被回收,ThreadLocal关联的线程共享变量还存在)。

虽然ThreadLocal的get,set方法可以清除ThreadLocalMap中key为null的value,但是get,set方法在内存泄露后并不会必然调用,所以为了防止此类情况的出现,我们有两种手段。

1、使用完线程共享变量后,显示调用ThreadLocalMap.remove方法清除线程共享变量;

2、JDK建议ThreadLocal定义为private static,这样ThreadLocal的弱引用问题则不存在了。

我这儿整理了比较全面的JAVA相关的面试资料,

需要领取面试资料的同学,请加群:473984645

threadlocal内存泄露_ThreadLocal用法详解和原理相关推荐

  1. threadlocal内存泄露_ThreadLocal 简介

    本文转载于SegmentFault社区 作者:莫小点还有救 1. ThreadLocal简介 通常情况下,我们创建的变量是可以被任何一个线程访问并修改的.如果想实现每一个线程都有自己的专属本地变量该如 ...

  2. threadlocal内存泄露_ThreadLocal原理解析

    谈一谈不常见却又不可少的ThreadLocal 在写ThreadLocal之前,需要先巩固下一点相关知识:Java内存模型及共享变量的可见性. 内存模型中所有变量存储在主内存中,当一个线程中要使用某个 ...

  3. ThreadLocal用法详解和原理

    转载自 https://blog.csdn.net/danengbinggan33/article/details/73105838 一.用法 ThreadLocal用于保存某个线程共享变量:对于同一 ...

  4. python内存池_python内存监控工具memory_profiler和guppy的用法详解

    python内存监控工具memory_profiler和guppy的用法详解 发布时间:2020-08-21 19:44:58 来源:脚本之家 阅读:123 python2.7在内存管理上相比pyth ...

  5. linux 内存 参数,linux free命令参数及用法详解(linux查看内存命令)

    linux free命令参数及用法详解(linux查看内存命令) 2019年05月31日 | 萬仟网科技 | 我要评论 free指令会显示内存的使用情况,包括实体内存,虚拟的交换文件内存,共享内存区段 ...

  6. python 内存分析工具_python内存监控工具memory_profiler和guppy的用法详解

    python2.7在内存管理上相比python3还是有些坑的,其释放后的内存仍然保留在python的内存池中,不被系统所用.python循环引用的变量不会被回收,这会导致程序越运行,占用的内存越大.我 ...

  7. 关于GCC/LLVM编译器中的sanitize选项用处用法详解

    关于GCC/LLVM编译器中的sanitize选项用处用法详解 ​ 编译器中sanitize选项原本来自google的开源C/C+ +工具集sanitizers项目, 包括了AddressSaniti ...

  8. c++智能指针用法详解

    随笔 - 209   文章 - 2   评论 - 174 c++ 智能指针用法详解 本文介绍c++里面的四个智能指针: auto_ptr, shared_ptr, weak_ptr, unique_p ...

  9. RxJava flatMap操作符用法详解

    RxJava系列文章目录导读: 一.RxJava create操作符的用法和源码分析 二.RxJava map操作符用法详解 三.RxJava flatMap操作符用法详解 四.RxJava conc ...

最新文章

  1. yield( )函数的使用
  2. 平面设计师如何训练自己创意思维
  3. 【转载】Android数据库(SqlLite)操作和db文件查看
  4. 一个简单的Ajax例子
  5. ubuntu升级python_Ubuntu 升级python3为更高版本【已实测】
  6. 面试题 HashMap和HashTable有什么区别
  7. 计算机知识点小报,制作电脑小报的教案
  8. C++关联容器,STL关联容器
  9. python 字符串编码解码和格式化问题
  10. layui totalRow 多层嵌套json_自定义 Behavior,实现嵌套滑动、平滑切换周月视图的日历...
  11. H.265编码和H.264编码的区别
  12. 坐标系转换--筛选高于RMS的强源-------ska暑期训练
  13. c语言实现简单俄罗斯方块
  14. 机器人潘森护盾_新版潘森无伤抗塔 还能抵消死歌大招?E技能护盾机制全解析...
  15. python3 基础语法分享
  16. progisp下载时报错Chip Enable Program Error 后续解决
  17. 如何实现上传多个图片并依次展示_如何在一页PPT中插入多张图片,并保持其美感...
  18. 计算机系统结构的分类-复杂指令集系统CISC与精简指令集系统RISC
  19. 音频codec调试心得
  20. 2018年上半年阅读书单

热门文章

  1. ora-00054:resource busy and acquire with nowait specified
  2. ASP.NET的视图(Razor)循环产生html代码
  3. 限时授权复制文件 1.0(2015.9.2更新)
  4. A Filter of Java URL Encoding: GetQueryStringEn...
  5. Serializable中的serialVersionUID
  6. python-同步(互斥)锁、递归锁、同步条件(event)
  7. 《第一行代码》学习笔记11-活动Activity(9)
  8. ASP.NET获取IP地址与MAC地址方法
  9. 带参数的插入语句的问题
  10. MFC初探 —— Editcontrol实现多行显示