Java - InheritableThreadLocal 跨线程泄漏数据

标签 java multithreading jetty threadpool

场景:

我正在运行一个由 Jetty 提供服务的 Java Web 应用程序。我使用 InheritableThreadLocal 在调用 API 时存储一些数据,然后在 API 调用进一步操作(在同一线程中)时访问这些数据。我存储这些数据的方式是:

代码:

public class RequestDataHolder {

    protected static final InheritableThreadLocal<RequestData> reqData = new InheritableThreadLocal<RequestData>();

    public static void setRequestData(RequestData request) {
        reqData.set(request);
    }

    public static void removeRequestData() {
        reqData.remove();
    }

    public static RequestData getRequestData() {
        return (RequestData) reqData.get();
    }

}

public class RequestData {
   private String requestId;
   private String apiStartTime;

   // getters and setters
}

问题:

  1. 当两个 API 调用并行发生时,我发现有时 Thread-1 会看到 Thread-2 设置的 RequestData 对象。这里是否存在数据泄露的可能性?
  2. 我是否正确使用静态方法来设置和获取 InheritableThreadLocal?

编辑

我看到一种行为:

  1. Thread-1 在 ITL 中设置 RequestData 并继续。
  2. 线程 2 在 ITL 中设置 RequestData 并继续。
  3. Thread-1 执行对数据库的调用。
  4. 线程 2 正在处理并修改 RequestData。
  5. Thread-1 醒来并搜索 RequestData,但发现设置的 RequestData 是 Thread-2。

当线程执行 I/O 时,Jetty 中的线程管理方式可能会发生什么情况吗?这里是否有可能因为线程重用而出现父子线程?

最佳答案

终于,我解决了这个问题。

推理:

出现这个问题的原因是,尽管 Java 的 InheritableThreadLocal 保证两个线程不会看到彼此的线程,但是在此变量中放入的内容并不能保证免 protected 跨线程可见。

示例:

例如,对象“RequestData”位于堆上。现在考虑这一系列事件:

  1. Thread-1 调用 ITL 上的集合并设置 RequestData 对象
  2. Thread-2 是从 Thread-1 派生的子线程。由于性质 的 ITL,线程 2 获取 ITL转移
  3. Thread-2 在 ITL 上执行 get 操作以检索 RequestData。现在,这个 对象将具有与设置的对象相同的哈希代码 第 1 步。
  4. 因此,如果您修改 Thread-2 中的任何内容,最终都会更新 该引用也将在 Thread-1 中可见。

证明推理的示例代码:

    public class Test implements Runnable {

        @Override
        public void run() {
            RequestData requestData = new RequestData();
            System.out.println("Thread ID: Setting requestData with hash code:" + requestData.hashCode());
            RequestDataHolder.setRequestData(requestData);
            Thread child = new Thread(new Runnable() {
                @Override
                public void run() {
                    RequestData requestData = RequestDataHolder.getRequestData();
                    System.out.println("Thread ID: Retrieved requestData with hash code:" + requestData.hashCode());
                }
            });
            child.start();
        }

        public static void main(String[] args) {
            Thread thread = new Thread(new Test());
            thread.start();
        }

    }

关于Java - InheritableThreadLocal 跨线程泄漏数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38679291/

相关文章:

java - 尝试将工具栏包含到使用 NavDrawer 模板的应用程序中

eclipse - App Engine 预览在 Eclipse 中不起作用

spring-boot - 如何将 Spring WebClient 与 Jetty 一起使用,而不是 Netty?

java - 如何才能实现对某个主题的消息只处理一次?

java - SearchView 过滤器 ListView

java - @Test 创建新记录

java - 关于使用另一个 Web 服务的 Web 服务的建议

c# - 等待方法什么时候退出程序?

Java 线程 - 这是同步的正确使用吗

java - Jersey 2 多部分