java threadlocal原理_【java】ThreadLocal线程变量的实现原理和使用场景

一.ThreadLocal线程变量的实现原理

1.ThreadLocal核心方法有这个几个

get()、set(value)、remove()

2.实现原理

ThreadLocal在每个线程都会创建一个线程内对应的T的副本,本T数据可以在本线程内任何地方可以被使用。线程之间互相不影响,所以是线程安全的。

3.底层结构

ThreadLocal实现各个线程数据副本的存取,是通过操作它的内部类ThreadLocalMap,进行键值对的存取和移除。

4.set(value)方法的底层

public voidset(T value) {

Thread t=Thread.currentThread();

ThreadLocalMap map=getMap(t);if (map != null)

map.set(this, value);elsecreateMap(t, value);

}

voidcreateMap(Thread t, T firstValue) {

t.threadLocals= new ThreadLocalMap(this, firstValue);

}

private void set(ThreadLocal>key, Object value) {//We don't use a fast path as with get() because it is at//least as common to use set() to create new entries as//it is to replace existing ones, in which case, a fast//path would fail more often than not.

Entry[] tab=table;int len =tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e =tab[i];

e!= null;

e= tab[i =nextIndex(i, len)]) {

ThreadLocal> k =e.get();if (k ==key) {

e.value=value;return;

}if (k == null) {

replaceStaleEntry(key, value, i);return;

}

}

tab[i]= newEntry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >=threshold)

rehash();

}

set(value)

1》根据当前线程,获取本线程所拥有的TreadLocalMap,如果没有,则创建一个新的。

2》ThreadLocalMap的即。【这里的ThreadLocal对象在set处,是根据本对象的hashCode经过计算获取到下标,然后循环对比Entry[]中每一个Entry的key进行插入或覆盖操作】

3》那么可以看出结构是:

3.1》每一个Thread有一个对应的ThreadLocalMap。Map的即

3.2》set操作根据ThreadLocal对象的hashCode对比Entry[]数组,进行新增插入或覆盖操作。

5.get()方法底层

publicT get() {

Thread t=Thread.currentThread();

ThreadLocalMap map=getMap(t);if (map != null) {

ThreadLocalMap.Entry e= map.getEntry(this);if (e != null) {

@SuppressWarnings("unchecked")

T result=(T)e.value;returnresult;

}

}returnsetInitialValue();

}

private Entry getEntry(ThreadLocal>key) {int i = key.threadLocalHashCode & (table.length - 1);

Entry e=table[i];if (e != null && e.get() ==key)returne;else

returngetEntryAfterMiss(key, i, e);

}

privateT setInitialValue() {

T value=initialValue();

Thread t=Thread.currentThread();

ThreadLocalMap map=getMap(t);if (map != null)

map.set(this, value);elsecreateMap(t, value);returnvalue;

}

protectedT initialValue() {return null;

}

get()

1》根据当前Thread线程,获取本线程的ThreadLocalMap

2》然后将键,也就是本ThreadLocal作为键传入,从Map中获取value。【获取的过程即,根据ThreadLocal对象的hashCode经过计算获取下标,根据下标取出Entry[]数组中的具体值,返回结果】

3》如果没有值,则返回null。

6.remove()底层

public voidremove() {

ThreadLocalMap m=getMap(Thread.currentThread());if (m != null)

m.remove(this);

}

remove()

1》本线程结束以前,一定要调用remove,清除线程变量中本次的变量。防止内存泄漏

二.ThreadLocal使用场景

拦截器存储 调用接口的用户信息,在本次Request到达,处理,直到返回的本线程中,都可以使用线程变量中的用户信息。

1.定义线程变量

public classRequestData {//线程变量 租户对象

public static final ThreadLocal TENEMENT_USER = new ThreadLocal();

2.到达controller之前的拦截器中,赋值线程变量。request返回之前remove【防止内存泄漏】

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

importjava.net.URLDecoder;importjava.net.URLEncoder;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importorg.apache.commons.lang3.StringUtils;importorg.springframework.web.servlet.HandlerInterceptor;importorg.springframework.web.servlet.ModelAndView;importcom.alibaba.fastjson.JSON;importcom.pisen.cloud.luna.core.enums.LunaHeaderNames;importcom.pisen.cloud.luna.core.interceptor.utils.LunaInterceptorUtil;importcom.pisen.cloud.luna.core.reqmodal.RequestData;importcom.pisen.cloud.luna.core.utils.TenementUser;public class TenementAuthinterceptor implementsHandlerInterceptor{

@Overridepublic booleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throwsException {

String tenInfo=request.getHeader(LunaHeaderNames.TENEMENT_INFO.getName());

TenementUser tuser= null;if(StringUtils.isNotBlank(tenInfo)){try{

tenInfo= URLDecoder.decode(tenInfo, "UTF-8");

tuser= JSON.parseObject(tenInfo,TenementUser.class);if(tuser != null){if(StringUtils.isBlank(tuser.getTenementId()) ||StringUtils.isBlank(tuser.getLoginName())){

tuser= null;

}else{

RequestData.TENEMENT_USER.set(tuser);

}

}

}catch(Exception e) {

e.printStackTrace();

}

}if(tuser != null){return true;

}else{

String errorMsg= "登录失败,请重新登录!";

LunaInterceptorUtil.ErrorResp(response,errorMsg);return false;

}

}

@Overridepublic voidpostHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

ModelAndView modelAndView)throwsException {

RequestData.TENEMENT_USER.remove();

}

@Overridepublic voidafterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throwsException {

}

}

View Code

3.controller中使用线程变量

//创建单据

@RequestMapping(value = "/insert",method =RequestMethod.POST)public AjaxResultinsert(@RequestBody SaleBill bill){

TenementUser tuser= RequestData.TENEMENT_USER.get();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值