我有一个带有true的java appengine应用程序。我知道多个线程将在处理多个并发请求的单个实例上运行。我知道代码必须是线程安全的,即没有全局静态变量。
我不明白的是,当请求结束时线程是否被杀死,或者一旦完成处理请求,是否可以使用相同的线程来处理另一个传入请求。
为什么这很重要?一些细节:
我有一个带有线程局部变量的静态类:
public abstract class Foo {
private static final ThreadLocal<Boolean> threadIsApiCall = new ThreadLocal<Boolean>();
static {
setIsApiCall(false);
}
}
此变量存储此线程的当前请求是对我们的rest api的调用,还是来自我们自己的自定义客户端的调用。仅当匹配我们的api路径的过滤器运行时,才会设置此变量。我遇到的问题是,如果向我们的API发出请求,并且threadlocal变量设置为true,则在后续请求(不是api请求)上,threadlocal变量仍设置为true。由于静态初始化程序,您会怀疑它会被设置为false。唯一可以设置为true的方法仍然是初始化程序没有运行,这使我相信线程被重用。这是真的吗?
答案 0 :(得分:3)
线程重用是servlet实现的实现细节。线程通常通过线程池重用。这通常可以通过servlet配置进行配置。不幸的是,GAE并非如此。
您可以通过记录Thread.currentThread().getName()
来检查GAE是否回收线程。
由于可能的线程重用,在servlet中使用ThreadLocal
总是一个坏主意。如果需要在请求范围中存储某些数据,请使用servletRequest.setAttribute(..)
。
答案 1 :(得分:0)
静态{...}只被调用一次(每个类加载器,当类首次加载到内存中时)。
您需要为每个线程设置theadlocal值:
public abstract class Foo {
private static final ThreadLocal<Boolean> threadIsApiCall = new ThreadLocal<Boolean>();
public static void yourFirstMethodInvokedByCustomClient() {
threadIsApiCall.set(false);
}
public static void yourFirstMethodInvokedByRESTAPI() {
threadIsApiCall.set(true);
}
public static void anotherLaterMethod() {
boolean isAPI = threadIsAPICall.get();
...
}
}