Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How springboot uses ThreadLocal

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article will explain in detail how springboot uses ThreadLocal. The editor thinks it is very practical, so I share it with you as a reference. I hope you can get something after reading this article.

Springboot uses ThreadLocal

An instance of thread closure using ThreadLocal in spring boot.

First create an instance that contains the ThreadLocal member variable:

Public class RequestHolder {private final static ThreadLocal requestHolder = new ThreadLocal (); public static void add (Long id) {requestHolder.set (id);} public static Long getId () {return requestHolder.get ();} public static void remove () {requestHolder.remove ();}}

Write a Controller class and request the test () method of the class to get the id stored in ThreadLocal:

Import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody; @ Controller@RequestMapping ("/ threadLocal") public class ThreadLocalController {@ RequestMapping ("/ test") @ ResponseBody public Long test () {return RequestHolder.getId ();}

Write a filter to add the id of the current thread to the Servlet before the request reaches the ThreadLocal (request-> tomcat container-> filter- > servlet- > inteceptor- > controller):

Import com.mmall.concurrency.example.threadLocal.RequestHolder;import lombok.extern.slf4j.Slf4j; import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import java.io.IOException Slf4jpublic class HttpFilter implements Filter {@ Override public void init (FilterConfig filterConfig) throws ServletException {} @ Override public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest; log.info ("do filter, {}, {}", Thread.currentThread () .getId (), request.getServletPath ()) / / add the id RequestHolder.add (Thread.currentThread (). GetId ()) of the current thread to ThreadLocal; filterChain.doFilter (servletRequest, servletResponse);} @ Override public void destroy () {}}

Write an interceptor to clear the id in ThreadLocal to avoid memory leaks when the request processing is complete (after returning from Controller).

Import com.mmall.concurrency.example.threadLocal.RequestHolder;import lombok.extern.slf4j.Slf4j;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse; @ Slf4jpublic class HttpInterceptor extends HandlerInterceptorAdapter {@ Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info ("preHandle"); return true @ Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info ("ThreadId:" + RequestHolder.getId ()); RequestHolder.remove (); log.info ("afterCompletion"); return;}}

Finally, we need to register our defined Filer and Inteceptor on the spring boot startup class and set the intercept path.

Import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @ SpringBootApplicationpublic class ConcurrencyApplication extends WebMvcConfigurerAdapter {public static void main (String [] args) {SpringApplication.run (ConcurrencyApplication.class, args);} @ Bean public FilterRegistrationBean httpFilter () {FilterRegistrationBean registrationBean = new FilterRegistrationBean () RegistrationBean.setFilter (new HttpFilter ()); registrationBean.addUrlPatterns ("/ threadLocal/*"); return registrationBean;} @ Override public void addInterceptors (InterceptorRegistry registry) {registry.addInterceptor (new HttpInterceptor ()) .addPathPatterns ("/ *");}}

Enter http://localhost:8080/threadLocal/test in the browser or postman

Observe the output:

2018-11-09 11 s.b.c.e.t.TomcatEmbeddedServletContainer 16V 51.287 INFO 34076-[main] s.b.c.e.t.TomcatEmbeddedServletContainer: Tomcat started on port (s): 8080 (http)

2018-11-09 11 c.m.concurrency.ConcurrencyApplication 16 Started ConcurrencyApplication in 51.290 INFO 34076-[main] c.m.concurrency.ConcurrencyApplication: Started ConcurrencyApplication in 1.718 seconds (JVM running for 2.132)

2018-11-09 11 INFO 1715 03.060 INFO 34076-[nio-8080-exec-2] o.a.c.c..[ tomcat] .[ localhost]. [/]: Initializing Spring FrameworkServlet 'dispatcherServlet'

2018-11-09 11 o.s.web.servlet.DispatcherServlet 1715 03.060 INFO 34076-[nio-8080-exec-2] o.s.web.servlet.DispatcherServlet: FrameworkServlet 'dispatcherServlet': initialization started

2018-11-09 11 o.s.web.servlet.DispatcherServlet 1715 03.072 INFO 34076-[nio-8080-exec-2] o.s.web.servlet.DispatcherServlet: FrameworkServlet 'dispatcherServlet': initialization completed in 12 ms

2018-11-09 11 com.mmall.concurrency.HttpFilter 1715 03.078 INFO 34076-[nio-8080-exec-2] com.mmall.concurrency.HttpFilter: do filter, 29, / threadLocal/test

2018-11-09 11 com.mmall.concurrency.HttpInterceptor 1715 03.090 INFO 34076-[nio-8080-exec-2] com.mmall.concurrency.HttpInterceptor: preHandle

2018-11-09 11 com.mmall.concurrency.HttpInterceptor 1715 03.124 INFO 34076-[nio-8080-exec-2] com.mmall.concurrency.HttpInterceptor: ThreadId:29

2018-11-09 11 com.mmall.concurrency.HttpInterceptor 1715 03.124 INFO 34076-[nio-8080-exec-2] com.mmall.concurrency.HttpInterceptor: afterCompletion

From the printed log results, we see that we added the id 29 of the current thread to the ThreadLocal in Filter, and then printed and deleted the id in Inteceptor.

The pit of ThreadLocal in use of springboot

ThreadLocal is suitable for scenarios where variables are isolated between threads and shared between methods or classes. Now I use the following scenarios in Springboot:

Create a Web application using Spring Boot, and use ThreadLocal to store a value of Integer that temporarily represents the user information that needs to be saved in the thread, which is initially null. In the business logic, I first get the value from ThreadLocal, then set the external parameters to ThreadLocal to simulate the logic of getting user information from the current context, then get the value again, and finally output the value and thread name twice.

@ RestControllerpublic class threadLocal {private ThreadLocal currentUser = ThreadLocal.withInitial (()-> null); @ RequestMapping ("wrong") public Map wrong (@ RequestParam ("userId") Integer userId) {/ / query the user information in ThreadLocal String before = Thread.currentThread (). GetName () + ":" + currentUser.get (); / / set user information to ThreadLocal currentUser.set (userId) / / after setting the user information, query the user information in ThreadLocal String after = Thread.currentThread (). GetName () + ":" + currentUser.get (); / / summarize and output two query results Map result = new HashMap (); result.put ("before", before); result.put ("after", after) Return result;}}

To reproduce the problem quickly, I set the parameter Tomcat in the configuration file to set the maximum number of threads in the worker pool to 1, so that the same thread is always processing the request:

Server.tomcat.max-threads=1

After running the program, first let user 1 to request the interface, you can see that the first and second access to the user ID is null and 1, respectively, in line with expectations: then user 2 to request the interface, this time there is a Bug, the first and second access to user ID is 1 and 2 respectively, obviously the first time to get the information of user 1, the reason is that the thread pool of Tomcat reuses threads.

The business code running under the Web server such as Tomcat is already running in a multithreaded environment, so you can't think that there will be no thread safety problems without explicitly opening multithreading, so when using tools like ThreadLocal to store some data, you need to pay special attention to explicitly emptying the set data after the code is run. You will also encounter the same problem if you use a custom thread pool in your code. The modified code is as follows:

@ RestControllerpublic class threadLocal {private ThreadLocal currentUser = ThreadLocal.withInitial (()-> null); @ RequestMapping ("wrong") public Map wrong (@ RequestParam ("userId") Integer userId) {/ / query the user information in ThreadLocal String before = Thread.currentThread (). GetName () + ":" + currentUser.get (); / / set user information to ThreadLocal currentUser.set (userId) Try {/ / set the user information and then query the user information in ThreadLocal String after = Thread.currentThread (). GetName () + ":" + currentUser.get (); / / aggregate output two query results Map result = new HashMap (); result.put ("before", before); result.put ("after", after) Return result;} finally {/ / add removal processing currentUser.remove ();}} this is the end of the article on "how springboot uses ThreadLocal". I hope the above content can be helpful to you so that you can learn more knowledge. if you think the article is good, please share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report