Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 处理并发用户的多线程GAE servlet_Java_Multithreading_Google App Engine_Servlets - Fatal编程技术网

Java 处理并发用户的多线程GAE servlet

Java 处理并发用户的多线程GAE servlet,java,multithreading,google-app-engine,servlets,Java,Multithreading,Google App Engine,Servlets,我希望对我的GAE servlet进行多线程处理,以便同一实例上的同一servlet可以同时处理来自不同用户的多达10个并发请求(在前端实例上,我相信最大线程数是10个),在每个用户之间进行时间分配 public class MyServlet implements HttpServlet { private Executor executor; @Override public void doGet(HttpServletRequest request, HttpSe

我希望对我的GAE servlet进行多线程处理,以便同一实例上的同一servlet可以同时处理来自不同用户的多达10个并发请求(在前端实例上,我相信最大线程数是10个),在每个用户之间进行时间分配

public class MyServlet implements HttpServlet {
    private Executor executor;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        if(executor == null) {
            ThreadFactory threadFactory = ThreadManager.currentRequestFactory();
            executor = Executors.newCachedThreadPoolthreadFactory);
        }

        MyResult result = executor.submit(new MyTask(request));

        writeResponseAndReturn(response, result);
    }
}
所以基本上,当GAE启动时,当它第一次收到对这个servlet的请求时,就会创建一个执行器,然后保存它。然后,每个新的servlet请求都使用该执行器生成一个新线程。显然,
MyTask
中的所有内容都必须是线程安全的


我关心的是这是否真的像我希望的那样。也就是说,这段代码是否创建了一个能够同时处理来自多个用户的多个请求的非阻塞servlet?如果没有,为什么我需要做什么来修复它?总的来说,GAE大师还能发现什么是完全错误的吗?提前谢谢。

我认为您的代码不起作用

doGet
方法正在servlet容器管理的线程中运行。当一个请求进入时,一个servlet线程被占用,直到
doGet
method返回,它才会被释放。在您的代码中,
executor.submit
将返回一个
Future
对象。要获得实际结果,您需要在
Future
对象上调用
get
方法,它将一直阻塞,直到
MyTask
完成其任务。只有在这之后,
doGet
方法返回,新的请求才能启动

我不熟悉GAE,但根据,您可以将servlet声明为线程安全的,然后容器将并行地向每个web服务器发送多个请求:

<!-- in appengine-web.xml -->
<threadsafe>true</threadsafe>

真的

您含蓄地问了两个问题,所以让我回答这两个问题:

1。如何让AppEngine实例处理多个并发请求?

你只需要做两件事:

  • 将语句
    true
    添加到
    appengine web.xml
    文件中,您可以在
    war\web-INF
    文件夹中找到该文件
  • 确保请求处理程序中的所有代码实际上是线程安全的,即在
    doGet(…)
    doPost(…)
    等方法中仅使用局部变量,或者确保同步对类或全局变量的所有访问
  • 这将告诉AppEngine实例服务器框架,您的代码是线程安全的,并且您允许它在不同的线程中多次调用所有请求处理程序,以同时处理多个请求。注意:好的,不可能将此设置为每个servlet。因此,您的servlet必须是线程安全的

    因此,本质上,您发布的执行器代码已经包含在每个AppEngine实例的服务器代码中,并且实际上从AppEngine为每个请求创建(或重用)的单独线程的run方法内部调用您的
    doGet(…)
    方法。基本上,
    doGet()
    已经是您的
    MyTask()

    文档的相关部分在这里(尽管它并没有说太多):

    2。张贴的代码是否对此(或任何其他)用途有用?

    AppEngine的当前形式不允许您创建和使用自己的线程来接受请求。它只允许您使用您提到的
    currentRequestThreadFactory()
    方法在
    doGet(…)
    处理程序中创建线程,但只允许对这一个请求执行并行处理,而不允许并行接受第二个请求(这发生在
    doGet()
    之外)

    名称
    currentRequestThreadFactory()
    在这里可能有点误导。这并不意味着它将返回
    请求线程
    当前
    工厂,即处理请求的线程。这意味着它返回一个
    工厂
    ,该工厂可以在
    当前请求
    中创建
    线程
    。因此,不幸的是,实际上甚至不允许在当前
    doGet()
    执行的范围之外使用返回的ThreadFactory,就像您建议的那样,基于它创建一个执行器并将其保留在类变量中

    对于前端实例,当
    doGet()
    方法返回时,在
    doGet()调用中创建的任何线程都将立即终止。对于后端实例,您可以创建保持运行的线程,但由于不允许打开服务器套接字以接受这些线程内的请求,因此这些线程仍不允许您自己管理请求处理

    您可以在appengine servlet中找到关于您可以做什么和不可以做什么的更多详细信息:

    (特别是螺纹部分)

    为了完整性,让我们看看如何使您的代码“合法”:

    下面的代码应该可以工作,但是对于代码能够并行处理多个请求来说,这并没有什么区别。这将完全由appengine-web.xml中的
    true
    设置决定。所以,从技术上讲,这段代码效率很低,它将一个基本上是线性的程序流分割到两个线程上。但无论如何,这就是:

    public class MyServlet implements HttpServlet {
    
        @Override
        public void doGet(HttpServletRequest request, HttpServletResponse response) {
            ThreadFactory threadFactory = ThreadManager.currentRequestThreadFactory();
            Executor executor = Executors.newCachedThreadPool(threadFactory);
    
            Future<MyResult> result = executor.submit(new MyTask(request)); // Fires off request handling in a separate thread
    
            writeResponse(response, result.get()); // Waits for thread to complete and builds response. After that, doGet() returns
        }
    }
    
    或者,更好的方法是将代码从MyTask.call()移到doGet()方法中

    放在一边-关于您提到的10个并发servlet线程的限制:

    这是一个(临时)设计决策,允许谷歌更轻松地控制服务器上的负载(特别是servlet的内存使用)

    您可以在此处找到有关这些问题的更多讨论:

    这个话题也一直困扰着我,因为我非常相信超精简的servlet代码,所以我通常的servlet可以轻松地处理数百个(如果不是数千个)的servlet
    public class MyServlet implements HttpServlet {
    
        @Override
        public void doGet(HttpServletRequest request, HttpServletResponse response) {
            writeResponse(response, new MyTask(request).call()); // Delegate request handling to MyTask object in current thread and write out returned response
        }
    }
    
    private static Executor executor;