案例代码:

FastThreadLocal 与 ThreadLocal 的使用方法一致

  1. package fastThreadLocal;
  2. import io.netty.util.concurrent.FastThreadLocal;
  3. import java.text.SimpleDateFormat;
  4. import java.util.Date;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. /**
  8. * FastThreadLocal案例
  9. * @date 2022年04月25日 9:00
  10. */
  11. public class FastThreadLocalDemo {
  12. private static FastThreadLocal<SimpleDateFormat> threadLocal = new FastThreadLocal<SimpleDateFormat>(){
  13. @Override
  14. protected SimpleDateFormat initialValue() throws Exception {
  15. return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
  16. }
  17. };
  18. public static void main(String[] args) {
  19. ExecutorService threadPool = Executors.newFixedThreadPool(10);
  20. for (int i = 0; i < 1000; i++) {
  21. int index = i;
  22. threadPool.execute(()-> {
  23. Date date = new Date(1000*index);
  24. String timeStr = threadLocal.get().format(date);
  25. System.out.println("线程时间:" + timeStr);
  26. //每次执行完后创建一个新
  27. threadLocal.set(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));
  28. });
  29. }
  30. threadPool.shutdown();
  31. threadLocal.remove();
  32. }
  33. }

image.png

创建过程:

进入 FastThreadLocal 源码查看其构造方法,在每次创建出一个新 FastThreadLocal 对象时会通过原子类自增出专属的 index(索引),当创建出 Integer.MAX_VALUE - 8 个 FastThreadLocal 后将会抛出异常
image.png

get方法:

尝试获取当前线程的 InternalThreadLocalMap ,InternalThreadLocalMap 内维护了一个数组,数组内的下标与线程 index 对应,通过 index(索引)即可获取到当前线程保存在 FastThreadLocal 的对象
第一次获取对象 v 会返回 unset,因此会执行 initialize 方法,initialize 方法调用重写的 initialize 方法进行数组初始化操作
image.png
image.png
image.png

进入 InternalThreadLocalMap.get(); 方法,首先会判断当前线程是否属于 FastThreadLocalThread,如果不属于 FastThreadLocalThread 线程,执行 slowGet() 方法(通过JDK的ThreadLocal实现),如果属于,执行 fastGet() 方法

slowGet方法执行逻辑:
1、使用 ThreadLocal 创建出没有初始化的全局 InternalThreadLocalMap
2、如果创建出的 InternalThreadLocalMap 获取为 null,创建新 InternalThreadLocalMap 放入 ThreadLocal 中·
3、返回该线程的 InternalThreadLocalMap

fastGet 方法执行逻辑:
1、获取当前线程的 threadLocalMap
2、如果获取为空,创建出新的 threadLocalMap

image.png

set 方法:

主要分为三步:
1、获取ThreadLocalMap (参考 get 方法讲解 )
2、直接通过索引set对象
3、移除对象
image.png