当前位置:网站首页>Principle and application of ThreadLocal
Principle and application of ThreadLocal
2022-07-04 18:44:00 【What is happiness】
ThreadLocal Principle and use
Recently, I saw a piece of code in the system management component of the company to obtain personnel information :
// Get login user information
UserLoginInfo userLoginInfo = ThreadLocalUtils.getUserLoginInfo();
getUserLoginInfo() The method was originally thought to be through token Parse or pass token check redis. But when I click in, I find that it's from ThreadLocal Get login information in ?
private static final ThreadLocal<Map<String, Object>> local = ThreadLocal.withInitial(HashMap::new);
public static UserLoginInfo getUserLoginInfo() {
return get(Constants.USER_LOGIN_INFO);
}
/** * from ThreadLocal Get the value * * @param key key * @param <T> Value generics * @return value , Returns if it does not exist null, If the type is inconsistent with the generic , May throw out {@link ClassCastException} * @see Map#get(Object) * @see ClassCastException */
public static <T> T get(String key) {
return ((T) local.get().get(key));
}
After some study, baidu found Threadlocal Data isolation between threads . At this time, I think of what I learned before volatile Ensure the visibility of data variables . Why is data isolated and visible . What's the difference ? Can't help being confused , The following is a personal comb
volatile
volatile yes Java One of the keywords of , A shared variable ( Member variables of class 、 Static member variable of class ) By volatile After modification , It has two layers of semantics : It ensures the visibility of different threads when operating on this variable and prohibits instruction reordering .
Java Medium variables are stored in main memory , Threads cannot directly read and manipulate variables in main memory , Instead, variables will be read into working memory for operation . and volatile The function of is to ensure that all threads can get the latest value of variables at the first time . But here's the thing , Yes volatile Modification of variables is not atomic . Because the change operation includes reading variables , Modify variables and write to working memory . and volatile It's just a guarantee that The read variable is the latest value read . therefore ,volatile There is no guarantee that any operation on variables is atomic .
ThreadLocal
ThreadLocal A separate copy of the variable is provided for each thread that uses the variable , Ensure the isolation between threads . Explore the bottom ,ThreadLocal Is through static inner classes ThreadLocalMap Realized .
Here is ThreadLocal Class diagram structure of , It can be seen from the picture that :Thread There are two variables in the class threadLocals and inheritableThreadLocals, Both ThreadLocal Inner class ThreadLocalMap Variable of type , We look inside ThreadLocalMap It can be found that it is actually similar to a HashMap

Different from what I thought , The local variables of each thread are not stored in ThreadLocal In the example , Instead, it is placed on the of the calling thread ThreadLocals In variables ( I said that before , The variable is Thread The class variables ). in other words ,ThreadLocal Local variables of type are stored in specific thread space , It is itself equivalent to a tool shell for loading local variables , adopt set Methods will value Added to the calling thread threadLocals in , When the calling thread calls get Methods can be learned from its threadLocals Take variables out of .
set Method
public void set(T value) {
//(1) Get the current thread ( Caller thread )
Thread t = Thread.currentThread();
//(2) Take the current thread as the key value , To find the corresponding thread variable , Find the corresponding map
ThreadLocalMap map = getMap(t);
//(3) If map Not for null, Add local variables directly ,key For the currently defined ThreadLocal Variable this quote , The value is the added local variable value
if (map != null)
map.set(this, value);
//(4) If map by null, Description first added , You need to create the corresponding map
else
createMap(t, value);
}
In the code above ,(2) In the call getMap Method to obtain the corresponding of the current thread threadLocals( Refer to the above illustration and text description ), The method code is as follows
ThreadLocalMap getMap(Thread t) {
return t.threadLocals; // Get the thread's own variables threadLocals, And bind to the member variables of the current calling thread. threadLocals On
}
If the getMap Method return value is not null, Just put value The value is set to threadLocals in (key Reference for current thread , The value is a local variable ); If getMap Method returns null Description is the first call set Method ( We talked about that earlier ,threadLocals The default value is null, Only a call set Method is created map), At this point, you need to call createMap Method creation threadLocals, The method is as follows
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
createMap Method not only creates threadLocals, The local variable value to be added is also added to the threadLocals in .
get Method
stay get Method implementation , First, get the current caller thread. , If the current thread's threadLocals Not for null, Directly return the local variable value bound by the current thread , Otherwise execution setInitialValue Method initialization threadLocals Variable . stay setInitialValue In the method , Be similar to set Method implementation , Are used to judge the current thread threadLocals Is the variable null, Yes, add local variables ( At this time, due to initialization , So the added value is null), Otherwise create threadLocals Variable , Similarly, the added value is null
public T 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;
return result;
}
}
return setInitialValue();
}
threadLocal and threadLocalMap The relationship is shown in the following figure .

threadlocal Memory leak problem
As we can see in the picture above ,threadLocal In the end, it's called threadlocalMap Class method , and threadlocalMap The interior of is actually a Entry Array
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
At present ThreadLocal References to k Be passed on to WeakReference Constructor for , therefore ThreadLocalMap Medium key yes ThreadLocal The weak references . If key threadlocal by null 了 , This entry It's cleared .
When threadlocal by null Or after being recycled , but ThreadLocalMap(threadlocals) Is the internal property of the thread , Its life cycle is synchronized with its thread . It won't be recycled . So at this time ThreadLocalMap(threadlocals) There will be a phenomenon :key It's empty , however value The value is still there . This is the memory leak problem .
Avoid it
Calling ThreadLocal Finally, we must call remove() Method .
Then the article begins with threadLocal Get user login information in . Found an interceptor in the project , Every request will token The user information obtained in is stored in threadLocal in . It's like this service Layer code can be passed directly threadlocal obtain , You don't need to pass... Through parameters .
/** * @author LSWXXY-WQ */
@Slf4j
public class UserInterceptor extends HandlerInterceptorAdapter {
@Autowired
UserService userService;
@Autowired
MenuService menuService;
@Resource
private AuthorizationService authorizationService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// obtain token
String token = request.getHeader(Constants.USER_TOKEN_HEADER);
// adopt token Get user information and put it in ThreadLocal in
if (StringUtil.isBlank(token) ) {
UserloginInfo userloginInfo = userService.getLoginInfo(token)
ThreadLocalUtils.setUserLoginInfo(userloginInfo);
}
// A series of subsequent verifications, etc
.....
.....
.....
.....
return super.preHandle(request, response, handler);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// Empty after business threadlocal
ThreadLocalUtils.clear();
super.afterCompletion(request, response, handler, ex);
}
At the end of the paper, the of the project is attached threadLocalUtils Well . The core is still right ThreadLocal Of get、set Use
public final class ThreadLocalUtils {
private ThreadLocalUtils() {
}
private static final ThreadLocal<Map<String, Object>> local = ThreadLocal.withInitial(HashMap::new);
/** * @return threadLocal All values in */
public static Map<String, Object> getAll() {
return local.get();
}
/** * Set a value to ThreadLocal * * @param key key * @param value value * @param <T> The type of value * @return The value put * @see Map#put(Object, Object) */
public static <T> T put(String key, T value) {
local.get().put(key, value);
return value;
}
/** * Delete the value corresponding to the parameter * * @param key * @see Map#remove(Object) */
public static void remove(String key) {
local.get().remove(key);
}
/** * Empty ThreadLocal * * @see Map#clear() */
public static void clear() {
local.remove();
}
/** * from ThreadLocal Get the value * * @param key key * @param <T> Value generics * @return value , Returns if it does not exist null, If the type is inconsistent with the generic , May throw out {@link ClassCastException} * @see Map#get(Object) * @see ClassCastException */
public static <T> T get(String key) {
return ((T) local.get().get(key));
}
/** * from ThreadLocal Get the value , And specify a provider when the value does not exist * * @see Supplier * @since 3.0 */
public static <T> T get(String key, Supplier<T> supplierOnNull) {
return ((T) local.get().computeIfAbsent(key, k -> supplierOnNull.get()));
}
/** * Get a value and delete * * @param key key * @param <T> Value type * @return value , Returns if it does not exist null * @see this#get(String) * @see this#remove(String) */
public static <T> T getAndRemove(String key) {
try {
return get(key);
} finally {
remove(key);
}
}
public static void setUserLoginInfo(UserLoginInfo loginInfo) {
put(Constants.USER_LOGIN_INFO, loginInfo);
}
public static UserLoginInfo getUserLoginInfo() {
return get(Constants.USER_LOGIN_INFO);
}
public static void setAppLoginInfo(AppLoginInfo loginInfo) {
put(Constants.APP_LOGIN_INFO, loginInfo);
}
public static AppLoginInfo getAppLoginInfo() {
return get(Constants.APP_LOGIN_INFO);
}
public static void setAppName(String appName) {
put(Constants.APP_NAME, appName);
}
public static String getAppName() {
return get(Constants.APP_NAME);
}
public static void setSysLog(SysLog sysLog){
put(Constants.OPERATE_LOG,sysLog);
}
public static SysLog getSysLog(){
return get(Constants.OPERATE_LOG);
}
}
边栏推荐
- Lua emmylua annotation details
- Just today, four experts from HSBC gathered to discuss the problems of bank core system transformation, migration and reconstruction
- [mathematical modeling of graduate students in Jiangxi Province in 2022] analysis and code implementation of haze removal by nucleation of water vapor supersaturation
- ISO27001 certification process and 2022 subsidy policy summary
- 力扣刷题日记/day2/2022.6.24
- 2022年全国CMMI认证补贴政策|昌旭咨询
- celebrate! Kelan sundb and Zhongchuang software complete the compatibility adaptation of seven products
- 项目通用环境使用说明
- VMware Tools和open-vm-tools的安装与使用:解决虚拟机不全屏和无法传输文件的问题
- Scala基础教程--14--隐式转换
猜你喜欢
随机推荐
一、C语言入门基础
Li Kou brush question diary /day5/2022.6.27
Implementation of shell script replacement function
Once the "king of color TV", he sold pork before delisting
Wireshark packet capturing TLS protocol bar displays version inconsistency
NBA赛事直播超清画质背后:阿里云视频云「窄带高清2.0」技术深度解读
力扣刷题日记/day1/2022.6.23
LD_LIBRARY_PATH 环境变量设置
如何提高开发质量
How is the entered query SQL statement executed?
ByteDance dev better technology salon was successfully held, and we joined hands with Huatai to share our experience in improving the efficiency of web research and development
[HCIA continuous update] WAN technology
删除二叉搜索树中的节点附图详解
SIGMOD’22 HiEngine论文解读
[go language question brushing chapter] go conclusion chapter | introduction to functions, structures, interfaces, and errors
With an estimated value of 90billion, the IPO of super chip is coming
Unity makes revolving door, sliding door, cabinet door drawer, click the effect of automatic door opening and closing, and automatically play the sound effect (with editor extension code)
力扣刷题日记/day2/2022.6.24
【211】go 处理excel的库的详细文档
ISO27001认证办理流程及2022年补贴政策汇总








![[HCIA continuous update] WAN technology](/img/31/8e9ed888d22b15eda5ddcda9b8869b.png)
