ThreadLocal VS FastThreadlocal

举报
赵KK日常技术记录 发表于 2023/06/24 13:15:39 2023/06/24
【摘要】 ThreadLocal:线程局部,但更多听到是线程局部变量,所谓局部即:单个线程内变量可共享,在并发线程中见到他的概率更多,但解决的并非线程安全问题。This class provides thread-local variables. These variables differ fromtheir normal counterparts in that each thread that...

ThreadLocal:线程局部,但更多听到是线程局部变量,所谓局部即:单个线程内变量可共享,在并发线程中见到他的概率更多,但解决的并非线程安全问题。

This class provides thread-local variables. These variables differ from

  • their normal counterparts in that each thread that accesses one (via its
  • {@code get} or {@code set} method) has its own, independently initialized
  • copy of the variable. {@code ThreadLocal} instances are typically private
  • static fields in classes that wish to associate state with a thread (e.g.,
  • a user ID or Transaction ID).
    ThreadLocal源码中写道

这个类提供线程局部变量。 这些变量与其正常的对应方式不同,因为访问一个的每个线程(通过其get或set方法)都有自己独立初始化的变量副本。 ThreadLocal实例通常是希望将状态与线程关联的类中的私有静态字段(例如,用户ID或事务ID)
1.如果多个线程访问同一个共享Threadlocal变量,是保证线程隔离的,A,B,C访问的即Threadlocal的变量副本

2.与线程状态相关,单个线程内,该线程持有该资源变量是私有的
Threadlocal并不是为了保证线程安全,而是为了在线程内方便共享变量跨方法的传递
package com.atkk.kk.netty.websocket;

public class ThreadLocalDemo {
public static ThreadLocal<Order> orderThreadLocal = new ThreadLocal<>();

public static void main(String[] args) {
    Order order = new Order();
    System.out.println(order.hashCode());
    orderThreadLocal.set(order);
    EntityBussiness1 entityBussiness1 = new EntityBussiness1();
    其他线程下是隔离的
    new Thread(()->{
        EntityBussiness2 entityBussiness2 = new EntityBussiness2();
        entityBussiness2.run();
    }).start();
    entityBussiness1.run();
}

static class EntityBussiness1{
    public void run(){
        Order order = orderThreadLocal.get();
        if(order == null){
            System.out.println("threadlocal == null in thread: " + Thread.currentThread().getName());
            return;
        }
        System.out.println(order.hashCode());
    }
}

static class EntityBussiness2{
    public void run(){
        Order order = orderThreadLocal.get();
        if(order == null){
            System.out.println("threadlocal == null in thread: " + Thread.currentThread().getName());
            return;
        }
        System.out.println(order.hashCode());
    }
}

}

此时两个方法获取的实体类hashcode值是一致的,在新线程下不能共享变量所以第二个对象为null

205125520
205125520
threadlocal == null in thread: Thread-0
应用场景:在Httpclient下共享返回码,cookie等等

public class HttpClient {
private static ThreadLocal<Integer> httpState = new ThreadLocal<Integer>(); // http 本次请求返回的状态码
private static ThreadLocal<String> httpCookieString = new ThreadLocal<String>(); // http 本次请求返回的cookie getRs 用这个方法时有效

/**

  • 最好能在过滤器里面调用下该方法,可以减少内存消耗
    */
    public static void removeThreadLocal(){
    httpState.remove();
    httpCookieString.remove();
    }
    }
    新听到一个组件叫BdUtil,其实现是基于Threadlocal的实现来写的,说起来项目中的应用场景不多,不适用于多线程分布式框架的传参。
    FastThreadlocal 更快的Theadlocal
    如果你看过Netty的源码,其中 io.netty.util.concurrent包下有一个非常类似的FastThreadlocal,其构造方法与其非常相似,但是网上所说其性能是Threadlocal的3倍,是Threadlocal的变体。
    A special variant of {@link ThreadLocal} that yields
    higher access performance when accessed from a
    {@link FastThreadLocalThread}.
    private static FastThreadLocal<Integer> fastThreadLocal = new FastThreadLocal<>();
public static void main(String[] args) {
  //if (thread instanceof FastThreadLocalThread) 使用FastThreadLocalThread更优,普通线程也可以
  new FastThreadLocalThread(() -> {
    for (int i = 0; i < 100; i++) {
      fastThreadLocal.set(i);
      System.out.println(Thread.currentThread().getName() + "====" + fastThreadLocal.get());
      try {
        Thread.sleep(200);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }, "fastThreadLocal1").start();


  new FastThreadLocalThread(() -> {
    for (int i = 0; i < 100; i++) {
      System.out.println(Thread.currentThread().getName() + "====" + fastThreadLocal.get());
      try {
        Thread.sleep(200);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }, "fastThreadLocal2").start();
}

Connected to the target VM, address: ‘127.0.0.1:60863’, transport: ‘socket’
17:08:00.714 [main] DEBUG io.netty.util.internal.logging.InternalLoggerFactory - Using SLF4J as the default logging framework
17:08:00.728 [main] DEBUG io.netty.util.internal.InternalThreadLocalMap - -Dio.netty.threadLocalMap.stringBuilder.initialSize: 1024
17:08:00.731 [main] DEBUG io.netty.util.internal.InternalThreadLocalMap - -Dio.netty.threadLocalMap.stringBuilder.maxSize: 4096
fastThreadLocal1====0
fastThreadLocal2====null
fastThreadLocal2====null
fastThreadLocal1====1
fastThreadLocal1====2
fastThreadLocal2====null
fastThreadLocal1====3
fastThreadLocal2====null
fastThreadLocal1====4
fastThreadLocal2====null
fastThreadLocal1====5
FastThreadLocal只有被的线程是FastThreadLocalThread或者其子类使用的时候才会更快,吞吐量我这边测试的效果大概3倍左右,但是如果是普通线程操作FastThreadLocal其吞吐量比ThreadLocal还差!
阿里TTL异步执行上下文对象传递
https://blog.csdn.net/boonya/article/details/55096596

吾常身不离鞍,髀肉皆消。今不复骑,髀里肉生。日月若驰,老将至矣,而功业不建,是以悲耳。 -----三国志》卷三十二〈蜀书·先主备传〉

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。