并发类相关的坑

Java 业务开发常见错误 100 例

Posted by Haiming on August 16, 2024

没有意识到线程重用导致用户信息错乱的 Bug

spring 是运行在tomcat容器之中的, tomcat 的工作线程是基于一个全局的线程池, 那么就是说实际上spring的线程是重复使用的,如果在使用 threadLocal 之前没有先清除, 而是直接进行使用, 就会造成问题.

@RequestMapping("/demo")
@RestController
@Log4j2
@Api("demo api")
public class DemoController {
    private static final ThreadLocal<Integer> currentUser = ThreadLocal.withInitial(() -> null);

    @GetMapping("wrong")
    public Map wrong(@RequestParam("userId") Integer userId) {
        //设置用户信息之前先查询一次ThreadLocal中的用户信息
        String before  = Thread.currentThread().getName() + ":" + currentUser.get();
        //设置用户信息到ThreadLocal
        currentUser.set(userId);
        //设置用户信息之后再查询一次ThreadLocal中的用户信息
        String after  = Thread.currentThread().getName() + ":" + currentUser.get();
        //汇总输出两次查询结果
        Map result = new HashMap();
        result.put("before", before);
        result.put("after", after);
        log.info("result: {}", result);
        return result;
    }
}

多次请求接口后, 结果:

Writing [{before=http-nio-8080-exec-5:12, after=http-nio-8080-exec-5:12}]