当前位置:网站首页>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);
}
}
边栏推荐
- Five thousand words to clarify team self-organization construction | Liga wonderful talk
- ISO27001认证办理流程及2022年补贴政策汇总
- 怎么开户才是安全的,
- 网上开户安全吗?是真的吗?
- [210] usage of PHP delimiter
- Thawte通配符SSL证书提供的类型有哪些
- 2022 national CMMI certification subsidy policy | Changxu consulting
- How to download files using WGet and curl
- 一直以为做报表只能用EXCEL和PPT,直到我看到了这套模板(附模板)
- I wrote a learning and practice tutorial for beginners!
猜你喜欢

How to modify icons in VBS or VBE

Li Kou brush question diary /day7/2022.6.29

. Net ORM framework hisql practice - Chapter 2 - using hisql to realize menu management (add, delete, modify and check)

ISO27001认证办理流程及2022年补贴政策汇总

MySQL common add, delete, modify and query operations (crud)

Once the "king of color TV", he sold pork before delisting

TCP两次挥手,你见过吗?那四次握手呢?

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)

Improve the accuracy of 3D reconstruction of complex scenes | segmentation of UAV Remote Sensing Images Based on paddleseg

机器学习概念漂移检测方法(Aporia)
随机推荐
Blue bridge: sympodial plant
一种将Tree-LSTM的强化学习用于连接顺序选择的方法
【209】go语言的学习思想
Scala基础教程--20--Akka
TCP两次挥手,你见过吗?那四次握手呢?
Nature microbiology | viral genomes in six deep-sea sediments that can infect Archaea asgardii
2022 national CMMI certification subsidy policy | Changxu consulting
输入的查询SQL语句,是如何执行的?
Li Kou brush question diary /day4/6.26
VMware Tools和open-vm-tools的安装与使用:解决虚拟机不全屏和无法传输文件的问题
Load test practice of pingcode performance test
[211] go handles the detailed documents of Excel library
6.26CF模拟赛B:数组缩减题解
ITSS运维能力成熟度分级详解|一文搞清ITSS证书
Li Kou brush question diary /day5/2022.6.27
Li Kou brush question diary /day6/6.28
[2022 Jiangxi graduate mathematical modeling] curling movement idea analysis and code implementation
Installation and use of VMware Tools and open VM tools: solve the problems of incomplete screen and unable to transfer files of virtual machines
Scala基础教程--18--集合(二)
The block:usdd has strong growth momentum