回顾ThreadLocal
ThreadLocal作为解决特定场景下并发的一种方案,在Spring等框架及面试中经常会被问到,它是Java必须要掌握的基础知识之一。
ThreadLocal类的作用是抽象线程内变量的抽象,这类对象只在线程生命周期内起作用,不会被其它线程访问修改,它可以减少线程内多个函数或组件之间传递信息的复杂度,并且这类变量不存在多线程并发访问问题从而时间性能更好。
一、ThreadLocal的实现原理
首先在线程抽象类Thread中有一个ThreadLocal.ThreadLocalMap类型的threadLocals引用,它指向的ThreadLocalMap类中有一个Entry[]数组,其中每个Entry对象key为ThreadLocal的实例对象,value值为ThreadLocal对象设置的值。其主要源码如下:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
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();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocal变量是在代码中定义,在代码执行时线程对象拿到自己ThreadLocalMap类型的成员变量的值(可看做一个Map),然后将ThreadLocal对象做为Key和ThreadLocal对象设置的对象值作为value组成的Entry对象加入进来。
由于ThreadLocal对象作为可以,所以必须要区分每个ThreadLocal的实例对象,为此ThreadLocal类定义中定义了如下成员:
private final int threadLocalHashCode = nextHashCode();
private static AtomicInteger nextHashCode = new AtomicInteger();
private static final int HASH_INCREMENT = 0x61c88647;
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
通过final int型的threadLocalHashCode成员区分不同的ThreadLocal对象,它在构造时通过nextHashCode()函数复制,而nextHashCode()又通过原子变量自增某个固定值来保证线程安全。
注意ThreadLocalMap并没有实现Map接口,它内部是一个Entry数组,里面每个Entry对象保存一个key-value键值对,key是ThreadLocal对象,value是ThreadLocal对象set方法设置的对象值。即通过ThreadLocal的set方法把ThreadLocal对象自己当做key,参数值当做value,放进了ThreadLocalMap中。ThreadLocalMap的Entry与HashMap的Entry相比没有next字段,因此不存在链表的情况,出现hash冲突时就将元素放到数组中下一个位置,其插入一个key-value的实现如下:
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
二、ThreadLocal可能引起的内存泄漏
ThreadLocal对象间的引用关系图如下,虚线表示弱引用,如果ThreadLocal对象没有外部强引用指向它,在系统gc时就会被回收,此时ThreadLocalMap中就会出现key为null的Entry,而程序中也无法访问这些key为null的Entry,但如果当前线程不结束的话(尤其是在线程池线程复用一直不结束的场景下),这个key为null的Entry的value就会一直存在一个从GcRoots过来的强引用链:Thread Ref——》Thread——》ThreadLocalMap——》Entry——》value,无法被内存回收,因此造成内存泄漏,即在threadLocal设为null和线程结束前这段时间内Entry不会被回收,造成了内存泄漏。

解决方法,ThreadLocal对象在使用完后调用remove方法删除它。
JDK也建议将ThreadLocal变量定义为private static的,这样ThreadLocal对象的生命周期就长(一直存在ThreadLocal对象的强引用,所以它不会被回收),从而能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,在用完后调用remove方法删除它。
https://www.cnblogs.com/xzwblog/p/7227509.html
回顾ThreadLocal的更多相关文章
- ThreadLocal内存泄漏真因探究(转)
出处: 链接:https://www.jianshu.com/p/a1cd61fa22da ThreadLocal原理回顾 ThreadLocal的原理:每个Thread内部维护着一个ThreadLo ...
- Java:ThreadLocal小记
Java:ThreadLocal小记 说明:这是看了 bilibili 上 黑马程序员 的课程 java基础教程由浅入深全面解析threadlocal 后做的笔记 内容 ThreadLocal 介绍 ...
- ThreadLocal的介绍与运用
ThreadLocal全面解析 学习目标 了解ThreadLocal的介绍 掌握ThreadLocal的运用场景 了解ThreadLocal的内部结构 了解ThreadLocal的核心方法源码 了解T ...
- 【Java EE 学习 54】【OA项目第一天】【SSH事务管理不能回滚问题解决】【struts2流程回顾】
一.SSH整合之后事务问题和总结 1.引入问题:DAO层测试 假设将User对象设置为懒加载模式,在dao层使用load方法. 注意,注释不要放开. 使用如下的代码块进行测试: 会报错:no sess ...
- 深入理解ThreadLocal(转)(2015年06月11日)
注明:转自:http://my.oschina.net/clopopo/blog/149368 学习一个东西首先要知道为什么要引入它,就是我们能用它来干什么.所以我们先来看看ThreadLocal对我 ...
- 线程知识-ThreadLocal使用详解
最近在看Spring的时候回顾了一下ThreadLocal,下面是ThreadLocal的使用说明. 概述 首先,谈到ThreadLocal的使用,我们先来了解一下ThreadLocal是什么?Thr ...
- 计算机程序的思维逻辑 (82) - 理解ThreadLocal
本节,我们来探讨一个特殊的概念,线程本地变量,在Java中的实现是类ThreadLocal,它是什么?有什么用?实现原理是什么?让我们接下来逐步探讨. 基本概念和用法 线程本地变量是说,每个线程都有同 ...
- 并发编程(四):ThreadLocal从源码分析总结到内存泄漏
一.目录 1.ThreadLocal是什么?有什么用? 2.ThreadLocal源码简要总结? 3.ThreadLocal为什么会导致内存泄漏? 二.ThreadLoc ...
- ThreadLocal源码解读
1. 背景 ThreadLocal源码解读,网上面早已经泛滥了,大多比较浅,甚至有的连基本原理都说的很有问题,包括百度搜索出来的第一篇高访问量博文,说ThreadLocal内部有个map,键为线程对象 ...
随机推荐
- Maven 的 settings.xml 配置中的mirror节点
maven2的setting.xml大家都知道,里面有个mirrors节点,用来配置镜像URL. mirrors可以配置多个mirror,每个mirror有id,name,url,mirrorOf属性 ...
- elbow 求拐点
distancePointLine <- function(x, y, slope, intercept) { ## x, y is the point to test. ## slope, ...
- 版本控制 version control
而版本控制能记录所有的操作,如创建删除增加,并能返回到之前的版本.版本控制通常需要同一些远程仓库配合使用,如GitHub 廖雪峰教学有 https://www.liaoxuefeng.com/wiki ...
- 【分布式搜索引擎】初识Elasticsearch
一.Elasticsearch是什么? Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎. Elasticsearch是一个实时分布式搜索和分析引擎.它让你以前所未 ...
- 文件下载 路径中有中文 报错 提示 文件找不到 java.io.FileNotFoundException: http://192.168.1.141:8096/resources/card/comcard/????????/????????.png
此问题主要是中文编码格式不对导致的,将路径中的中文部分设置下编码就可以啦 例如: String url = "http://192.168.1.141:8096/resources/car ...
- 3、VNC
VNC(Virtual Network Computing,虚拟网络计算机) VNC分为两部分组成:VNC server 和 VNC viewer VNC安装 1.yum install tigerv ...
- 『Numpy』内存分析_高级切片和内存数据解析
在计算机中,没有任何数据类型是固定的,完全取决于如何看待这片数据的内存区域. 在numpy.ndarray.view中,提供对内存区域不同的切割方式,来完成数据类型的转换,而无须要对数据进行额外的co ...
- Matlab:五点差分方法求解椭圆方程非导数边值问题
差分格式脚本文件: tic; clear clc M=32;%x的步数 N=16;%y的步数 h1=1/M;%x的步长 h2=1/N;%y的步长 x=0:h1:1; y=0:h2:1; u=zeros ...
- gdb pretty printer for STL debug in Linux
Check your gcc version. If it is less than 4.7, you need use another printer.py file. Get the file f ...
- Vue 学习Day001
入门 基本使用 安装Vue 直接引入本地或者cdn Vue地址 使用npm 使用cli 示例 <!DOCTYPE html> <html lang="en"> ...