子线程获取不到主线程的request信息?

springboot项目下,控制层发起任务,在service层开启一个thread线程执行相关操作,当控制层返回之后,子线程就获取不到主线程的request的相关信息,这应该怎么解决?


@Undest
controller:

public class ControllerReportController {
    private static InheritableThreadLocal<HttpServletRequest> threadLocalData = new InheritableThreadLocal<>();

    @Autowired
    ControllerReportService controllerReportService;

    @RequestMapping("/test")
    public void test(HttpServletRequest request) {
        String userId = request.getHeader("userId");
        log.info(userId);
        threadLocalData.set(request);
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                controllerReportService.test(threadLocalData);
            }
        });
        thread.start();
        log.info("主线程结束");
    }
}

service:

public class ControllerReportServiceImpl implements ControllerReportService {


    @Override
    public void test(InheritableThreadLocal<HttpServletRequest> threadLocalData) {
        try {
            Thread.sleep(5000);
        } catch (Exception e) {

        }
        HttpServletRequest httpServletRequest = threadLocalData.get();
        String userId = httpServletRequest.getHeader("userId");
        log.info(String.valueOf(userId));
    }
}

结果
[INFO ] [164] [2023-08-02 11:45:31] 293
[INFO ] [164] [2023-08-02 11:45:31] 主线程结束
[INFO ] [164] [2023-08-02 11:45:31] RequestId:1690947931271, 本次请求耗时SpeedTime:4ms
[INFO ] [745] [2023-08-02 11:45:36] null

阅读 2.9k
2 个回答

更新:
下面的代码经过我个人测试可以跑通:
Controller:

package com.example2.demo.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(value = "/test")
public class TestController {

    private static InheritableThreadLocal<HttpServletRequest> threadLocalData = new InheritableThreadLocal<>();

    @Autowired
    TestService testService;

    @RequestMapping("/check")
    @ResponseBody
    public void check(HttpServletRequest request) throws Exception {
        threadLocalData.set(request);
        System.out.println("父线程打印的id->" + request.getParameter("id"));
        
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                //服务层里写方法
                testService.doSomeThing(threadLocalData);
            }
        });
        thread.start();
        System.out.println("父线程方法结束");
    }

}

Service:

package com.example2.demo.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Service;

@Service("/testService")
public class TestService {

    public void doSomeThing(InheritableThreadLocal<HttpServletRequest> threadLocalData) {
        System.out.println("子线程打印的id->" +threadLocalData.get().getParameter("id"));
        System.out.println("子线程方法结束");
    }

    
}

请求:
image.png
结果:
image.png
可以看到在主线程返回后子线程依然能够拿到request里的值

在异步线程里不应该直接访问request对象本身。

可以把需要异步处理的信息从request对象中拿出来,传递给异步线程,但不要直接把request对象丢给异步线程访问。

以jetty的实现为例, 在Jetty中,request对象并不是每次请求都创建一个新对象,而是会被http线程复用的。所以,request对象如果被两个线程同时访问,会造成意想不到的错误。

我曾经因为这个问题排查了很久代码

其他web容器是否存在同样的限制和具体实现有关。

所以强烈不建议直接把request对象丢给异步线程持有。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏