当前位置:网站首页>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);
}
}
边栏推荐
- Li Kou brush question diary /day1/2022.6.23
- android使用SQLiteOpenHelper闪退
- Grain Mall (I)
- 力扣刷题日记/day4/6.26
- 6.26CF模拟赛B:数组缩减题解
- Stars open stores, return, return, return
- Halcon template matching
- LD_ LIBRARY_ Path environment variable setting
- ISO27001 certification process and 2022 subsidy policy summary
- Scala基础教程--17--集合
猜你喜欢
Li Kou brush question diary /day6/6.28
[2022 Jiangxi graduate mathematical modeling] curling movement idea analysis and code implementation
ISO27001 certification process and 2022 subsidy policy summary
Halcon模板匹配
Wireshark packet capturing TLS protocol bar displays version inconsistency
输入的查询SQL语句,是如何执行的?
一种将Tree-LSTM的强化学习用于连接顺序选择的方法
2022 national CMMI certification subsidy policy | Changxu consulting
Just today, four experts from HSBC gathered to discuss the problems of bank core system transformation, migration and reconstruction
The block:usdd has strong growth momentum
随机推荐
俄罗斯 Arenadata 发布基于PostgreSQL的产品
"In Vietnam, money is like lying on the street"
[cloud voice suggestion collection] cloud store renewal and upgrading: provide effective suggestions, win a large number of code beans, Huawei AI speaker 2!
What types of Thawte wildcard SSL certificates provide
【2022年江西省研究生数学建模】冰壶运动 思路分析及代码实现
表情包坑惨职场人
字节跳动Dev Better技术沙龙成功举办,携手华泰分享Web研发效能提升经验
Microservice architecture debate between radical technologists vs Project conservatives
蓝桥:合根植物
Scala基础教程--15--递归
TorchDrug教程
People in the workplace with a miserable expression
Grain Mall (I)
[211] go handles the detailed documents of Excel library
Load test practice of pingcode performance test
. Net ORM framework hisql practice - Chapter 2 - using hisql to realize menu management (add, delete, modify and check)
被忽视的问题:测试环境配置管理
力扣刷题日记/day7/2022.6.29
Reptile elementary learning
How is the entered query SQL statement executed?