场景:
我正在运行Jetty服务的Java Web应用程序。我在调用API时使用InheritableThreadLocal来存储一些数据,稍后当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
}
问题:
编辑
我看到一个行为:
可能会有一些东西,当线程执行I / O时,可能会继续在Jetty中管理线程的方式吗?由于线程重用,是否有可能出现父子线程?
最后,我想出了这个问题。
推理:
问题发生的原因是,即使Java的InheritableThreadLocal保证两个线程不会看到彼此,但是不能保证您在此变量中放置的内容不会在线程中可见。
例:
例如,对象“RequestData”存在于堆上。现在考虑这一系列事件:
示例代码证明推理:
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();
}
}
Jetty示例中的相关内容是Jetty从以前的工作线程生成新的工作线程。因此,如果Thread-1生成Thread-2,则在初始化InheritedThreadLocal
之后,从该点开始,两个线程对reqData具有相同的值。似乎InheritedThreadLocal
与Jetty结合使用是不安全的。
此外,由于RequestDataHolder.reqData
是static final
,如果这个类在主线程中很早就被初始化,由于InheritedThreadLocal
的性质,这个引用将被复制到所有子线程。