1.
Supplier
在了解ThreadLocal之前先来理解什么是
Supplier
在 Java 中,
Supplier
是一个函数式接口,位于java.util.function
包下,用于定义不接受参数但返回值的操作。它是 Java 8 引入的函数式编程特性之一,常用于延迟计算或提供默认值的场景。1. Supplier 接口的定义
java
@FunctionalInterface public interface Supplier<T> { T get(); // 唯一的抽象方法,返回类型为T的对象 } //解释 //@FunctionalInterface 注解的作用 //1.标记接口是函数式接口 // 增强可读性,明确告诉别人这是函数式接口。 //2.编译检查 // 如果你在接口上加了 @FunctionalInterface,编译器会确保接口 只有一个抽象方法。 // 如果不止一个抽象方法,编译器报错。 //3.注意:默认方法和静态方法不算抽象方法,所以不会影响函数式接口判断。 //@FunctionalInterface 不是必须的,即使不加,接口只要有一个抽象方法,也可以用 Lambda。 //4.加上注解的好处:编译器检查 + 提示别人这是函数式接口。
- 特点:
- 仅包含一个无参数的抽象方法
get()
。- 可用作 Lambda 表达式或方法引用的目标类型。
2. 核心用途
延迟计算:
只有在需要结果时才执行计算,避免不必要的资源消耗。提供默认值:
为方法或变量提供默认生成逻辑,例如ThreadLocal.withInitial()
。3. 使用示例
public class Cat { @Override public String toString() { return "Cat{" + "name='" + name + '\'' + '}'; } String name = "aa"; private static String getName(){ return "aa"; } public static void main(String[] args) { //Cat cat = new Cat(); //使用 Lambda 表达式 Supplier<String> supplierGetName = Cat::getName;// Cat::getName这样写getName只能是static方法或者构造方法 //等价于使用匿名内部类写法 Supplier<String> supplierGetName1 = new Supplier<String>() { @Override public String get() { //return cat.getName(); // 重点:调用的是外部 cat 的方法(静态方法和普通都行) return Cat.getName(); // 重点:和上面的Supplier<String> supplierGetName = Cat::getName;一致调用静态方法 } }; Supplier<Cat> supplierCat = Cat::new; String name = supplierGetName.get(); Cat cat1 = supplierCat.get(); System.out.println(cat1); //Cat{name='aa'} System.out.println(name); //aa } }
所以我们看到对于supplier可以使用get方法获取对应的函数的返回值
2.什么ThreadLocal
ThreadLocal
是 Java 中用于实现线程局部变量的核心类,它提供了线程级别的数据隔离机制。每个线程都可以通过ThreadLocal
独立访问自己的数据副本,不同线程之间的数据互不干扰。
每个
Thread
对象内部有一个ThreadLocalMap
(类似 HashMap)
ThreadLocal
作为 Key,存储的值作为 Value重点: ThreadLocal 变量本身(即定义的那个ThreadLocal对象)是共享的,被所有线程访问。但每个线程通过它获取到的值却是各自独立的。如下图也就是说线程Thread1和Thread2里面的ThreadLocalMap是不同的,ThreadLocalMap中以key-value的形式进行存储,其中
ThreadLocal
作为 Key,存储的值作为 Value,而每个Thread
对象内部有一个ThreadLocalMap,所以根据线程找到对应的
ThreadLocalMap,再根据ThreadLocal
作为 Key找到存储的Value的值
3.ThreadLocal的创建以及get解析
public class ThreadLocalTest { private List<String> messages = new ArrayList<>(); public static final ThreadLocal<ThreadLocalTest> holder = ThreadLocal.withInitial(ThreadLocalTest::new); public static void add(String message) { holder.get().messages.add(message); } public static void main(String[] args) { Thread t = new Thread(() -> { ThreadLocalTest.add("hello"); System.out.println(ThreadLocalTest.holder.get().messages); }); ThreadLocalTest.add("你好"); System.out.println(holder.get().messages); } }
1.分析withInitial方法都做了什么
public static final ThreadLocal<ThreadLocalTest> holder = ThreadLocal.withInitial(ThreadLocalTest::new);
1.点进withInitial方法我们可以看到
2.再次点进SuppliedThreadLocal方法
//验证要求不为空值 public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }
我们可以看到上面代码就相当于将suppplier赋值了ThreadLocalTest::new,并返回了SuppliedThreadLocal类型的对象
这也就是 ThreadLocal.withInitial(ThreadLocalTest::new);的全过程
2.分析holder.get()方法都做了什么
首先我们先了解Thread类中有个初始值为null的ThreadLocalMap对象
还要了解ThreadLocal类中getMap方法是获取Thread类的ThreadLocalMap对象
以及ThreadLocal类中createMap方法是设置当前线程[Thread类]中的threadLocals的值
//t为传入的线程,firstValue为一个对象 void createMap(Thread t, T firstValue) { //在当前例子中执行【get方法】 //以key为holder对象,firstValue为initialValue方法返回的ThreadLocalTest的实例对象 //给threadLocals赋值 t.threadLocals = new ThreadLocalMap(this, firstValue); }
点进get方法
//ThreadLocal类中的 get方法 public T get() { Thread t = Thread.currentThread(); //获取当前线程 //获取当前线程的threadLocals属性的值,由于初次访问Thread中的threadLocals值为null //上边有提到过[ThreadLocalMap]threadLocals为null ThreadLocalMap map = getMap(t); if (map != null) { //如果不为null,根据当前对象作为key获取map的键值对并 ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } //初次访问map肯定为null,所以走下面的代码 return setInitialValue(); } //ThreadLocal类中的 setInitialValue方法 private T setInitialValue() { T value = initialValue();//获取ThreadLocalTest的实例对象 Thread t = Thread.currentThread(); //获取当前线程 ThreadLocalMap map = getMap(t); //初次get方法map肯定为null,使用get方法肯定不会走if (map != null) //因为如果map不为null,那么在上边的get方法就直接返回ThreadLocalTest的实例对象了, //就不会进入setInitialValue方法了 if (map != null) map.set(this, value); //必走这个 else createMap(t, value); //设置当前线程[Thread]中的threadLocals的值 return value; } //ThreadLocal类中的 initialValue方法 protected T initialValue() { return null; } //这个方法是SuppliedThreadLocal类中重写ThreadLocal类的initialValue方法 //至于为什么走SuppliedThreadLocal中的initialValue呢? //因为在ThreadLocal<ThreadLocalTest> holder = //ThreadLocal.withInitial(ThreadLocalTest::new) //ThreadLocal.withInitial(ThreadLocalTest::new)返回的其实是SuppliedThreadLocal类型 //即上述代码为父类的引用指向子类的对象,所以调用的时候调用的是子类的initialValue方法 @Override protected T initialValue() { //supplier为第一步ThreadLocal.withInitial(ThreadLocalTest::new)过程中赋值的supplier //supplier的值为ThreadLocalTest::new return supplier.get(); //返回ThreadLocalTest的实例对象 } }
ThreadLocal--创建以及get源码解析
于 2025-07-14 22:05:05 首次发布