2

我有一个真正的java appengine应用程序。我知道多个线程将在处理多个并发请求的单个实例上运行。我知道代码必须是线程安全的,即没有全局静态变量。请求线程是否在http请求之间重用?

我不明白的是当请求结束时线程是否被终止,或者一旦处理完一个请求,是否可以使用同一个线程处理另一个传入请求。

这是为什么?一些细节:

我有一个线程局部变量的静态类这样:

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的方法仍然是如果初始化器不运行,这导致我认为线程被重用。这是真的?

回答

3

线程重用是servlet实现的实现细节。线程通常通过线程池重用。这通常可以通过servlet配置进行配置。不幸的是,GAE并非如此。

您可以简单地检查GAE是否通过登录Thread.currentThread().getName()来回收线程。

由于可能的线程重用,在servlet中使用ThreadLocal总是一个坏主意。如果您需要在请求范围内存储一些数据,请使用servletRequest.setAttribute(..)

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(); 
     ... 
    } 
} 
+0

感谢您的澄清,但线程可以重用吗?因为如果没有,那么下面的理论上应该是这样工作的: – aloo

+0

if(threadAdmin.get()!= null){ return threadAdmin.get()。booleanValue(); } else { return false; } ...然后只在APIFilter中将alue设置为true。这是我目前有的,但它不起作用。这就是为什么我认为线程正在被重用。因为如果它是一个新线程,那么.get()会返回null(因为它没有被设置为客户端调用)。 – aloo

+0

是的,根据其他答案,线程可以重用,这取决于您的服务器。我应该声明在另一个方法()中获取threadlocal只在同一个http请求处理上下文中有效,它不会在请求之间存储值。 –

相关问题