写在开始 :
本文主要讲述 : ThreadLocal简介; 常用API; demo案例; 特点引用场景;以及部分底层原理源码内容。
引言 :
从常见面试题看 ThreadLocal:
**①解释 **: ThreadLocal是多线程中对于解决线程安全的一个操作类,它会为每个线程都分
配一个独立的线程副本从而解决了变量并发访问冲突的问题。ThreadLocal 同时
实现了线程内的资源共享;
②案例:使用JDBC操作数据库时,会将每一个线程的Connection放入各自的
ThreadLocal中,从而保证每个线程都在各自的 Connection 上进行数据库的操
作,避免A线程关闭了B线程的连接。
public class ThreadLocalTest {
static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
new Thread(() -> {
String name = Thread.currentThread().getName();
threadLocal.set("itcast"); // set(v)方法 : 设置值
print(name);
System.out.println(name + "-after remove : " +
threadLocal.get()); // get()方法:获取值
}, "t1").start();
new Thread(() -> {
String name = Thread.currentThread().getName();
threadLocal.set("itheima");
print(name);
System.out.println(name + "-after remove : " +
threadLocal.get());
}, "t2").start();
}
static void print(String str) {
//打印当前线程中本地内存中本地变量的值
System.out.println(str + " :" + threadLocal.get());
//清除本地内存中的本地变量
threadLocal.remove(); // remove()方法 清除值
}
}
③源码
ThreadLocal本质来说就是一个线程内部存储类,从而让多个线程只操作自己内
部的值,从而实现线程数据隔离;
在ThreadLocal中有一个内部类叫做ThreadLocalMap,类似于HashMap
ThreadLocalMap中有一个属性table数组,这个是真正存储数据的位置
Ⅰ:set方法:
Ⅱ:get/remove方法
内存泄漏问题
每一个Thread维护一个ThreadLocalMap,在ThreadLocalMap中的Entry对象继承
了WeakReference。其中key为使用弱引用的ThreadLocal实例,value为线程变量
的副本;
引用类型 : ①弱引用:内存不太够时候优先回收;②强引用:不会被回收
使用 ThreadLocal 时候 ,强烈建议:务必手动remove。
正文第一部分–编程实战
1.ThreadLocal 简介
ThreadLocal 见名知意 : 线程本地 或者 本次线程;
但是从它实际作用而言, 可能解释为 【线程局部变量】or 【线程本地变量】更为合适。
2.ThreadLocal作用
ThreadLocal是java.lang包中的一个泛型类,可以实现为线程创建独有变量,这个变量对于其他线程是隔离的,也就是线程本地的值,这也是ThreadLocal名字的来源;
package java.lang
public class ThreadLocal<T>{
}
每个使用该变量的线程都要初始化一个完全独立的实例副本(也就是变量的本地拷贝),不存在多线程间共享问题
3.ThreadLocal的 API 方法
ThreadLocal用来存储当前线程的独有数据,相关API就是存值,取值,清空值的简单操作
- withInitial:创建一个ThreadLocal实例,并给定初始值【JDK8推出的新方法,一般都是用该方法初始化ThreadLocal】
- get:返回当前线程ThreadLocal的值,如果没有设置值返回null
- set:设置当前线程ThreadLocal的值
- remove:删除当前线程ThreadLocal的值
- initialValue:此方法默认返回null, 通过ThreadLocal构造方法初始化时一般重写此方法,来设置初始值,在JDK8之后通过withInitial方法初始化
4.初始化ThreadLocal
初始化ThreadLocal有三种方式:
- 直接通过构造方法创建,此时初始值为null
- 通过构造方法同时重写initialValue方法给定初始值
- 通过JDK8的withInitial()静态方法创建,可以通过Lambda直接给初始值【推荐使用】
①构造方法
@Test
public void test1() {
// 通过构造方法,初始化ThreadLocal
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
// 未给定初始值,通过get方法获取值为null
System.out.println(threadLocal.get());
}
@Test
public void test2() {
// 初始化ThreadLocal
ThreadLocal<Integer> threadLocal = new ThreadLocal<