【问题标题】:Servlet doesnt appear to execute in a threaded mannerServlet 似乎没有以线程方式执行
【发布时间】:2010-05-06 09:31:02
【问题描述】:

我使用运行 servlet 的 Tomcat 开发了一个简单的服务器。

servlet 调用命令行程序 - 执行大约需要 20 秒,然后通过 JSON 将结果返回给用户。问题是 - 如果我同时发出 2 个以上的请求,则 servlet 会阻塞,直到前面的请求之一完成。

下面是一个例子——“Im in”是servlet的顶部,结果列表是在servlet执行之后。所有请求都是同时提出的 - 但您可以清楚地看到它们没有同时处理。为了同时处理所有请求,我需要在 tomcat 中更改什么设置?

算我一个 算我一个 FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE 算我一个 FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE 算我一个 FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE 算我一个 FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE 算我一个 FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE 算我一个 FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE 算我一个 FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE

【问题讨论】:

  • 我不明白你的输出。尝试添加线程名称,以便您可以查看哪些线程处理您的请求。您可以通过调用 Thread.currentThread().getName() 来获取当前线程名称。此外,尝试将您的“Im in”消息与结果“关联”,即通过记住操作的开始时间并将其与结果一起写入(原子计数器会更好)。

标签: java tomcat servlets multithreading


【解决方案1】:

默认情况下同时处理对 servlet 的请求。没有启用/禁用此行为的设置。 JavaDoc for HttpServlet 证实了这一点:

Servlet 通常运行在 多线程服务器,所以要注意 servlet 必须处理并发 请求并注意同步 访问共享资源。

但是,如果您的 servlet 实现了标记接口 SingleThreadModel,则 servlet 一次只能处理一个请求。但是,使用此接口通常被认为是一种不好的做法,并且由于您没有提及它,因此我假设您没有使用它。

当然,即使您没有实现 SingleThreadModel,您也可以使用(可能不合适的)同步使任何 servlet 单线程,例如

class MyServlet extends HttpServlet {

  private void Object sharedObject = new Object()

  protected synchronized void doGet(HttpServletRequest req, HttpServletResponse resp) {
    // method logic goes here
  }

  protected void doPost(HttpServletRequest req, HttpServletResponse resp) {

    synchronized(sharedObject) {
      // method logic goes here
    }

  }

  protected void doPut(HttpServletRequest req, HttpServletResponse resp) {

    synchronized(this) {
      // method logic goes here
    }
  }
}

在上面的示例中,一次只能有一个线程执行相同的请求方法,尽管(例如)一个线程可以执行doPost(),而另一个线程正在执行doGet()

如果您不明白为什么会这样,那么我建议您在进一步调查您的问题之前阅读 Java 中的并发编程。

【讨论】:

  • 我的代码中没有提到 SingleThreadModel - 它扩展了 HttpServlet
  • 那么它必须是我在我调用的每个获取请求开始时的实现: System.out.println("Im in ");运行时 rt = Runtime.getRuntime();进程 pr = rt.exec( 它运行一个程序然后返回输出 - 但那是我认为它阻塞的位.... = 给出输出:Im in FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE Im in FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE Im in FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FVFNT17 STOP_IDLE Im in FVFNT01 STOP_IDLE FVFNT03 STOP_IDLE FVFNT16 STOP_IDLE FV
  • 我认为这是因为 Runtime.GetRuntime() 是静态的 - 这意味着一次只有一个调用......那么我如何在没有这个限制的情况下剥离子进程?跨度>
  • “静态 - 意味着一次只有一个调用” - 这是不正确的。那就是你说的同步。即使它是同步的,简单的 getter 无论如何都会很快返回。
  • 但看起来 getRuntime() 被阻塞了,也就是说,它一次只能分发 1 个?
【解决方案2】:

问题出在您的测试客户端中。它正在同步触发请求。它应该异步触发请求,然后 servlet 将能够执行相同的操作:)

大约 4 天前提出了同样的问题,我发布了一个带有代码示例的答案,测试客户端应该是什么样子:Servlet requests are executed sequentially for no apparent reason in Glassfish v3。您可能会发现它也很有用。

【讨论】:

  • 我的测试客户端是我的网络浏览器...您是否建议测试来自不同主机的触发请求是一个答案?
  • 不,在不同的线程(异步)中触发请求就是答案。您(基本上,网络浏览器是)在单线程(同步)中触发所有请求。我是否必须在此处复制粘贴链接的答案以便您阅读? :)
  • 对,所以在部署的场景中,这不会是一个问题,因为请求会异步进入。
【解决方案3】:

确保您的请求使用不同的 HTTP 连接,并检查您的 tomcat 配置是否允许超过 1 个线程(默认情况下允许,因此除非您更改它,否则应该没问题)。

【讨论】:

  • 当你说不同的连接 - 来自 localhost 的 10 个请求 - localhost 不会满足这个吗?
  • Localhost 是可以的,但是通过 1 个连接发送 10 个请求或通过 10 个连接发送 10 个请求是有区别的。如果所有请求都来自单个连接,则它们将按顺序处理。
【解决方案4】:

一旦您在 Tomcat 上运行您的应用程序(而不是在调试模式下通过 Eclipse),对同一服务器的相同请求将被线程化。

可以做一个简单的测试用例: 做一些简单的 doGet 来做接下来的事情:

PrintWriter printWriter = response.getWriter();
printWriter.append("doGet: Hello from testServlet! doing some thread check :)");
try{Thread.sleep(15*1000);}catch(Exception e){}
printWriter.close();

现在运行一个 Web 浏览器并多次运行这个 servlet,你会看到它们都同时返回(+-)。 如果 servlet 没有线程化,您会期望第一个将在 15 秒后返回,第二个将在 30 秒后返回,依此类推...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多