专栏首页赵KK日常技术记录ThreadLocal VS FastThreadlocal

ThreadLocal VS FastThreadlocal

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源码中写道

这个类提供线程局部变量。 这些变量与其正常的对应方式不同,因为访问一个的每个线程(通过其getset方法)都有自己独立初始化的变量副本。 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

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

本文分享自微信公众号 - 赵KK日常技术记录(gh_cc4c9f1a9521),作者:赵kk

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-01-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JAVA经典面试题讨论---类加载,多线程

    群里的小伙伴一个个都特别优秀,一大早便发来了小问题让大家讨论,简单讨论之后,要知其然,知其所以然,趁机巩固下近期知识

    疯狂的KK
  • java并发编程(三)

    为什么我锁了String的所有实例化对象,对Myobject没有加锁,他仍会互斥执行呢?

    疯狂的KK
  • java并发编程(四)

    volatile 解决的是多核CPU带来的缓存与CPU之间数据的可见性,实现禁止指令重排

    疯狂的KK
  • 深入分析Java的ThreadLocal

    上回书说,Android可以用Looper+Handler来实现线程通信的关键是在于Looper 回顾:深入了解Android的Looper Looper 在当...

    PhoenixZheng
  • 死磕Java之聊聊ThreadLocal源码(基于JDK1.8)

    记得在一次面试中被问到ThreadLocal,答得马马虎虎,所以打算研究一下ThreadLocal的源码

    haifeiWu
  • Java多线程:神秘的线程变量 ThreadLocal 你了解吗?

    Carson.Ho
  • Java高并发情况下的锁机制优化

    将大对象,拆成小对象,大大增加并行度,降低锁竞争. 如此一来偏向锁,轻量级锁成功率提高.

    大道七哥
  • Spring Cloud Alibaba:Sentinel实现熔断与限流

    JDK的并发包中提供了几个非常有用的并发工具类。 CountDownLatch、 CyclicBarrier和 Semaphore工具类提供了一种并发流程控制的...

    不会飞的小鸟
  • Java高并发之锁优化

    用户1216491
  • 并发编程之显式锁原理

    Synchronized 关键字结合对象的监视器,JVM 为我们提供了一种『内置锁』的语义,这种锁很简便,不需要我们关心加锁和释放锁的过程,我们只需要告诉虚拟机...

    Single

扫码关注云+社区

领取腾讯云代金券