【问题标题】:Subsequent REST call is blocked until previous one is finished后续 REST 调用被阻塞,直到前一个调用完成
【发布时间】:2013-11-04 18:08:13
【问题描述】:

我有 REST 服务

@Path("/rest")
@Component
public class MyRestService
{
    @Inject
    private MyBean bean;

    @GET
    @Path("/do")
    public String start()
    {
        this.logger.info("Before do " + Thread.currentThread().getId());
        String result = this.bean.do();
        this.logger.info("After do " + Thread.currentThread().getId());

        return result;
    }
}

调用注入的Spring单例bean的方法(内部有一些状态)

@Service
public class MyBean
{
    public String do()
    {
        // do something big...
    }
}

当我在浏览器中调用“.../rest/do”时,第一个调用按预期进行,但如果我在另一个选项卡中进行相同的调用,此调用将等待第一个调用完成以在同一线程中处理第二个调用。

如果我以“.../rest/do?async=true”进行第二次调用,它不会等待并在新线程中处理第二个请求,但如果我将两个请求都作为“.../rest/do? async=true" - 第二个再次等待第一个完成。

这种行为的原因可能是什么?真的是预期的吗?

我的 web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

    <display-name>My REst</display-name>

    <!-- spring configuration by annotations -->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>

    <!-- spring configuration class -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>app.Config</param-value>
    </context-param>

    <!-- to return data according to extension -->
    <context-param>
        <param-name>resteasy.media.type.mappings</param-name>
        <param-value>json : application/json, xml : application/xml</param-value>
    </context-param>

    <!-- this has to match with resteasy-servlet url-pattern -->
    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/rest</param-value>
    </context-param>

    <listener>
        <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
    </listener>

    <!-- resteasy spring connector (to use DI in rest-resources) -->
    <listener>
        <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>resteasy-servlet</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
    </servlet>

    <!-- this has to match with resteasy-servlet url-pattern -->
    <servlet-mapping>
        <servlet-name>resteasy-servlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

    <!-- Bind Jboss's TransactionManager (EntityManagerFactory) to JNDI -->
    <persistence-unit-ref>
        <persistence-unit-ref-name>persistence/ReferenceDataDS</persistence-unit-ref-name>
        <persistence-unit-name>ReferenceDataDS</persistence-unit-name>
    </persistence-unit-ref>
</web-app>

【问题讨论】:

  • 您的 servlet 容器可以配置为单线程。
  • 您向我们展示的内容中没有任何内容可以说明为什么会发生这种行为。
  • 这段代码非常好;但是这里的代码并没有以任何方式描述这种行为。您正在使用描述某处行为的 Spring,它只是将此代码用于请求定义。在您的容器或 Spring 中的某处有一个定义,它告诉它是单线程还是接受多个请求或其他东西。阅读 servlet 容器上的配置说明并尝试修改这些文本文件。
  • 有什么想法吗? :) 我在 web.xml 和 @Configuration 注释类中都没有看到关于“线程”的任何特别之处。
  • 按照您对 Q1 的回答,任何问题都在客户端。如果服务器可以同时处理来自不同客户端的请求,那么在 Spring 控制器中您无需执行任何操作。我怀疑您需要研究您正在使用的任何客户端库的预期行为。

标签: java multithreading spring rest resteasy


【解决方案1】:

您可以在调试模式下运行应用程序服务器来解决这个问题。使用两个不同的客户端进行测试,例如Firefox, Chrome, IE, Opera, ... 在等待答案时暂停所有线程。

  • 如果您看到只有一个工作线程处于活动状态,则说明应用服务器的设置存在问题。
  • 如果您看到多个工作线程处于活动状态,但其中一个正在等待信号量,则说明多个线程访问同一资源时存在问题
  • 如果您有多个工作线程处于活动状态,但其中一个正在等待与持久性存储的连接,那么您的数据源没有连接池。

【讨论】:

    【解决方案2】:

    因为我刚刚花了一整天的时间来解决这个确切的问题(没有意识到更改参数会导致并行执行):

    罪魁祸首是浏览器。

    • 在 Chrome 中,当您从两个选项卡调用相同的资源时,调用会排队,但当您从不同的窗口进行调用时会并行执行。
    • 在 IE11 中,它们总是并行执行
    • 在 Firefox 中,无论调用是来自不同的选项卡还是窗口,它们总是会排队。

    当 URL 略有不同时,它们都会通过添加不同的片段或参数来并行执行它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-05
      • 1970-01-01
      • 2015-05-11
      • 1970-01-01
      相关资源
      最近更新 更多