Netty学习之旅----ThreadLocal原理分析与性能优化思考(思考篇)

文章探讨了ThreadLocal的作用,它是如何作为线程执行环境的一部分,以及在数据库事务场景中的应用。重点分析了ThreadLocal的工作原理,尤其是ThreadLocalMap的实现,并提出了针对高并发场景的性能优化思路,如Netty的自定义实现。
摘要由CSDN通过智能技术生成

ThreadLocal,本地线程变量,每个线程保留着一个共享变量的副本。其实我不太认可每个线程保存共享变量的一个副本这个说法,而是ThreadLocal是线程上下文环境的一种实现方式而已。就以数据库事务这一常用场景来举例说明,比如每个线程需要访问数据库,就需要获取数据库的连接Connection对象,在实际中,我们会用数据库连接池来重复利用Connection,首先线程池,这里是一个共享变量,线程池的实现必须保证多个线程同时从线程池中获取Connection不会重复,然后每个线程使用单独的Connection,并且该Connection被一个线程占用后,其他线程压根就不会使用到,也不会试图去使用一个已经被其他线程占用的Connection对象。由于一个线程在执行过程中,可能需要多次操作数据库,所以我们的设计就是一个线程在执行过程中,只与一个Connection打交道,也就是整个线程的执行过程(执行环境)需要保存刚获取的Connection,最简单有效的办法,就是把这个Connection保存在线程对象的某个属性中,ThreadLocal就是干这事的。ThreadLocal并不是为这个Connection复制一份,多个线程都使用这个副本,不是这样的,一个Connection对象在任意时刻,没有被复制多份。

我的观点:ThreadLocal是线程一个本地变量,是线程的执行上下文。

2、 从ThreadLocal get方法源码分析其实现逻辑

==============================

/**

  • Returns the value in the current thread’s copy of this

  • thread-local variable. If the variable has no value for the

  • current thread, it is first initialized to the value returned

  • by an invocation of the {@link #initialValue} method.

  • @return the current thread’s value of this thread-local

*/

public T get() {

Thread t = Thread.currentThread(); //@1

ThreadLocalMap map = getMap(t); //@2

if (map != null) {

ThreadLocalMap.Entry e = map.getEntry(this); //@3

if (e != null)

return (T)e.value;

}

return setInitialValue(); // @4

}

代码@1:获取当前线程。

代码@2:从当前线程获取ThreadLocalMap。

ThreadLocalMap getMap(Thread t) {

return t.threadLocals;

}

这里是直接返回线程对象的threadLocals变量,有点意思吧,所以说ThreadLocal,是线程的本地变量,就是这层意思,真正存放数据的地方,就是线程对象本身,其实接下来的会更加有意思:我们进入ThreadLocalMap源码分析,得知,原来ThreadLocalMap就是一个Map结构(K-V)键值对,关于里面的源码就不一一分析了,ThreadLocalMap(ThreadLocal firstKey, Object firstValue),firstKey 为ThreadLocal,神奇吧,其实这也是为什么Thread的本地变量的数据类型为Map的原型,一个线程可以被多个ThreadLocal关联,每声明一个,就在线程的threadLocals增加为一个键值对,key 为 ThreadLocal,而value为具体存放的对象。

代码@3:如果线程的ThreadLocalMap不为空,则直接返回对,否则进入到代码@4

代码@4:初始化并获取放入ThreadLocal中的变量。

上面就是ThreadLocal的核心设计理念,为了更加直观的说明ThreadLocal原理,举例说明:


public class ThreadLocalDemo1 {

private static final ThreadLocal schemaLocal

= new ThreadLocal();

public void test1() {

String a = schemaLocal.get();

ThreadLocalDemo2 demo2 = new ThreadLocalDemo2();

demo2.test(a);

}

public static void main(String[] args) {

// TODO Auto-generated method stub

}

}

public class ThreadLocalDemo2 {

private static final ThreadLocal slocal = new ThreadLocal();

public void test(String b) {

String a = slocal.get();

// 其他代码

System.out.println(b);

}

public static void main(String[] args) {

// TODO Auto-generated method stub

}

}

public class TestMain {

public static void main(String[] args) {

// TODO Auto-generated method stub

ThreadLocalDemo1 d = new ThreadLocalDemo1();

d.test1();

}

}

一个线程调用 ThreadLocalDemo1 的 test1方法,在这个执行链中会涉及到两个ThreadLocal变量,调用ThreadLocal的get方法,首先会获取当前线程,然后从当前线程对象中获取线程内部属性[ThreadLocal.ThreadLocalMap threadLocals = null;],然后从ThreadLocalMap中以ThreadLocal对象为键,从threadLocals map中获取存放的值。

线程的threadLocals值为

{

ThreadLocalDemo1.schemaLocal  : 该变量中的值,

ThreadLocalDemo2.scloal : 存放在本线程中的值

}

3、 ThreadLocal优化思考

==================

ThreadLocal的数据访问算法,本质上就是Map的访问特性。

我在分析HashMap源码的时候,已经将HashMap的存储结构讲解完毕,如有兴趣,可以浏览一下我的博文:深入理解HashMap:http://blog.csdn.net/prestigeding/article/details/52861420,HashMap根据key的访问速度效率是很快的,为什么呢?因为HashMap根据key的hash,然后会定位到内部的数据槽(该数据是数组结构),众所周知,根据数组的下标访问,访问速度是最快的,也就是说HashMap根据key的定位速度比LinkedList等都快,仅次于数组访问方式,这是因为HashMap多了一步Hash定位槽的过程(当然,如果有Hash冲突那就更慢了)。所以,如果在高并发场景下,需要进一步优化ThreadLocal的访问性能,那就要从线程对象(Thread的threadLocals 数据结构下手了,如果能将数据结构修改为数组,然后每个ThreadLocal对象维护其下标那就完美了)。是的,Netty框架就是为了高并发而生的,由于并发访问的数量很大,一点点的性能优化,就会带来可观的性能提升效应,Netty主要从如下两个方面对ThreadLocal的实现进行优化

  • 线程对象直接提供 set、get方法,以便直接获取线程本地存储相关的变量属性。

  • 将数据存储基于数组存储。

4、Netty关于ThreadLocal机制的优化

=========================

由于ThreadLocal是JDK的原生实现,通用性很强,直接扩展进行定制化不是明智的选择,故Netty在优化ThreadLocal的方式是自己另起灶炉,实现ThreadLocal的语义。优化方法如下:

  • 提供一个接口,FastThreadLocalAccess,并对线程池工厂类进行定制,创建的线程继承在java.lang.Thread类,并实现FastThreadLocalAccess接口,提供直接设置,获取线程本地变量的方法。

  • 提供FastThreadLocal类,此类实现ThreadLocal相同的语义。

  • 提供InternalThreadLocalMap类,此类作用类同于java.lang.ThreadLocal.ThreadLocalMap类,用于线程存放真实数据的结构。

4.1 扩展线程对象,提供set,get方法


最后

即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!

我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!
一共有20个知识点专题,分别是:

Dubbo面试专题

JVM面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Java并发面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Kafka面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MongDB面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MyBatis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MySQL面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Netty面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

RabbitMQ面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Redis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Spring Cloud面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

SpringBoot面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

zookeeper面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

常见面试算法题汇总专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

计算机网络基础专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

设计模式专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

dJ4gWEO-1714430764605)]

SpringBoot面试专题

[外链图片转存中…(img-miG9ovLE-1714430764605)]

zookeeper面试专题

[外链图片转存中…(img-wGvBF5xR-1714430764606)]

常见面试算法题汇总专题

[外链图片转存中…(img-gVPRSJ4z-1714430764606)]

计算机网络基础专题

[外链图片转存中…(img-OQ2unhqg-1714430764607)]

设计模式专题

[外链图片转存中…(img-iHRLmXEs-1714430764607)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值