threadlocal内存泄露_ThreadLocal用法详解和原理
一、用法
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用法详解和原理相关推荐
- threadlocal内存泄露_ThreadLocal 简介
本文转载于SegmentFault社区 作者:莫小点还有救 1. ThreadLocal简介 通常情况下,我们创建的变量是可以被任何一个线程访问并修改的.如果想实现每一个线程都有自己的专属本地变量该如 ...
- threadlocal内存泄露_ThreadLocal原理解析
谈一谈不常见却又不可少的ThreadLocal 在写ThreadLocal之前,需要先巩固下一点相关知识:Java内存模型及共享变量的可见性. 内存模型中所有变量存储在主内存中,当一个线程中要使用某个 ...
- ThreadLocal用法详解和原理
转载自 https://blog.csdn.net/danengbinggan33/article/details/73105838 一.用法 ThreadLocal用于保存某个线程共享变量:对于同一 ...
- python内存池_python内存监控工具memory_profiler和guppy的用法详解
python内存监控工具memory_profiler和guppy的用法详解 发布时间:2020-08-21 19:44:58 来源:脚本之家 阅读:123 python2.7在内存管理上相比pyth ...
- linux 内存 参数,linux free命令参数及用法详解(linux查看内存命令)
linux free命令参数及用法详解(linux查看内存命令) 2019年05月31日 | 萬仟网科技 | 我要评论 free指令会显示内存的使用情况,包括实体内存,虚拟的交换文件内存,共享内存区段 ...
- python 内存分析工具_python内存监控工具memory_profiler和guppy的用法详解
python2.7在内存管理上相比python3还是有些坑的,其释放后的内存仍然保留在python的内存池中,不被系统所用.python循环引用的变量不会被回收,这会导致程序越运行,占用的内存越大.我 ...
- 关于GCC/LLVM编译器中的sanitize选项用处用法详解
关于GCC/LLVM编译器中的sanitize选项用处用法详解 编译器中sanitize选项原本来自google的开源C/C+ +工具集sanitizers项目, 包括了AddressSaniti ...
- c++智能指针用法详解
随笔 - 209 文章 - 2 评论 - 174 c++ 智能指针用法详解 本文介绍c++里面的四个智能指针: auto_ptr, shared_ptr, weak_ptr, unique_p ...
- RxJava flatMap操作符用法详解
RxJava系列文章目录导读: 一.RxJava create操作符的用法和源码分析 二.RxJava map操作符用法详解 三.RxJava flatMap操作符用法详解 四.RxJava conc ...
最新文章
- yield( )函数的使用
- 平面设计师如何训练自己创意思维
- 【转载】Android数据库(SqlLite)操作和db文件查看
- 一个简单的Ajax例子
- ubuntu升级python_Ubuntu 升级python3为更高版本【已实测】
- 面试题 HashMap和HashTable有什么区别
- 计算机知识点小报,制作电脑小报的教案
- C++关联容器,STL关联容器
- python 字符串编码解码和格式化问题
- layui totalRow 多层嵌套json_自定义 Behavior,实现嵌套滑动、平滑切换周月视图的日历...
- H.265编码和H.264编码的区别
- 坐标系转换--筛选高于RMS的强源-------ska暑期训练
- c语言实现简单俄罗斯方块
- 机器人潘森护盾_新版潘森无伤抗塔 还能抵消死歌大招?E技能护盾机制全解析...
- python3 基础语法分享
- progisp下载时报错Chip Enable Program Error 后续解决
- 如何实现上传多个图片并依次展示_如何在一页PPT中插入多张图片,并保持其美感...
- 计算机系统结构的分类-复杂指令集系统CISC与精简指令集系统RISC
- 音频codec调试心得
- 2018年上半年阅读书单
热门文章
- ora-00054:resource busy and acquire with nowait specified
- ASP.NET的视图(Razor)循环产生html代码
- 限时授权复制文件 1.0(2015.9.2更新)
- A Filter of Java URL Encoding: GetQueryStringEn...
- Serializable中的serialVersionUID
- python-同步(互斥)锁、递归锁、同步条件(event)
- 《第一行代码》学习笔记11-活动Activity(9)
- ASP.NET获取IP地址与MAC地址方法
- 带参数的插入语句的问题
- MFC初探 —— Editcontrol实现多行显示