?
整个线程的全局变量,不是程序的全局变量
线程内部的局部变量,不同的线程之间不会相互干扰
总结
- 线程并发:在多线程并发的场景下
- 传递数据:可以通过ThreadLocal在同一个线程,不同组件中传递公共变量
- 线程隔离:每个线程的变量都是独立的,不会互相影响
内部结构

demo
java
package com.jysemel.java.basic.thread.local;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class ThreadLocalDemo {
private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
new Thread(() -> {
for (int i = 0; i < 10; i++) {
threadLocal.set(UUID.randomUUID() + " T1");
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("T1 " + threadLocal.get());
}
}).start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
threadLocal.set(UUID.randomUUID() + " T2");
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("T2 " + threadLocal.get());
}
}).start();
}
}
内存泄露
ini
/**
* 内存泄露
*/
public class ThreadLocalDemo1 {
private static final ThreadLocal<byte []> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
executorService.execute(() -> {
byte[] bytes = new byte[10240*20240];
threadLocal.set(bytes);
// threadLocal.remove();
});
}
executorService.shutdown();
}
}
结果

原因
1、ThreadLocal对象存储在ThreadLocalMap中,当线程结束后,
ThreadLocalMap对象不会被回收,会一直保存在Thread对象中

解决内存泄露
ini
public class ThreadLocalDemo1 {
private static final ThreadLocal<byte []> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
executorService.execute(() -> {
byte[] bytes = new byte[10240*20240];
threadLocal.set(bytes);
threadLocal.remove();
});
}
executorService.shutdown();
}
}
ThreadLocal与Synchronized的区别
-
Synchronized
同步机制只提供了一份变量,其他线程只能等待,不能并发 多个线程之间访问资源的同步
-
ThreadLocal
每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰 多线程中让每个线程之间的数据相互隔离
jdk8前后区别
-
jdk8之前
ThreadLocalMap 作为 ThreadLocal 类的一个静态内部类,承担着存储线程局部变量 在这种设计模式下,无论一个进程中存在多少个不同的 ThreadLocal 实例, 它们都共享同一个 ThreadLocalMap 结构
-
jdk8之后
使得 ThreadLocalMap 不仅是 ThreadLocal 类的静态内部类, 同时也成为了 Thread 类的一个成员变量 。 每个线程都拥有自己独立的一个 ThreadLocalMap 实例,从而实现了更细粒度的数据隔离和管理
源码: public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { map.set(this, value); } else { createMap(t, value); } }
hash冲突如何解决
- 开放地址法解决hash冲突
- 当前插入的元素从冲突位置开始依次往后遍历,直到找到一个空闲位置

扩容
scss
源码:
private void rehash() {
expungeStaleEntries();
// Use lower threshold for doubling to avoid hysteresis
if (size >= threshold - threshold / 4)
resize();
}

markdown
1. 默认大小
ThreadLocalMap的初始容量是16。在创建ThreadLocalMap时,
会初始化一个长度为16的Entry数组。
2. 扩容机制
ThreadLocalMap的扩容阈值是初始容量的2/3,即当size达到阈值时,
就会进行扩容。扩容时,新容量是旧容量的2倍。