Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.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 弹簧&x27;s延迟的结果setResult与超时的交互_Java_Spring_Tomcat_Comet_Spring 3 - Fatal编程技术网

Java 弹簧&x27;s延迟的结果setResult与超时的交互

Java 弹簧&x27;s延迟的结果setResult与超时的交互,java,spring,tomcat,comet,spring-3,Java,Spring,Tomcat,Comet,Spring 3,我正在Tomcat上试验Spring的DeferredResult,我得到了疯狂的结果。是我做错了,还是春天或Tomcat里有虫子?我的代码很简单 @Controller public class Test { private DeferredResult<String> deferred; static class DoSomethingUseful implements Runnable { public void run() {

我正在Tomcat上试验Spring的
DeferredResult
,我得到了疯狂的结果。是我做错了,还是春天或Tomcat里有虫子?我的代码很简单

@Controller
public class Test {
    private DeferredResult<String> deferred;

    static class DoSomethingUseful implements Runnable {
        public void run() {
            try { Thread.sleep(2000); } catch (InterruptedException e) { }
        }
    }

    @RequestMapping(value="/test/start")
    @ResponseBody
    public synchronized DeferredResult<String> start() {
        deferred = new DeferredResult<>(4000L, "timeout\n");
        deferred.onTimeout(new DoSomethingUseful());
        return deferred;
    }

    @RequestMapping(value="/test/stop")
    @ResponseBody
    public synchronized String stop() {
        deferred.setResult("stopped\n");
        return "ok\n";
    }
}
我不认为我做错了什么。Spring文档似乎表示可以随时调用
setResult
,即使请求已经过期,也可以从任何线程(“ 应用程序可以从其选择的线程生成结果”)


使用的版本:Linux上的Tomcat 7.0.39,Spring 3.2.2。

这是一个很好的bug发现
为了更好地理解,只需添加更多关于bug()的信息

setResult()中有一个同步块,扩展到提交分派的部分。如果超时同时发生,这可能会导致死锁,因为Tomcat超时线程有自己的锁定,只允许一个线程执行超时或分派处理

详细说明:

当您在请求“超时”的同时调用“stop”时,两个线程正试图锁定DeferredResult对象“deferred”

  • 执行“onTimeout”处理程序的线程 以下是Spring文档的摘录:

    当异步请求在设置DeferredResult之前超时时,从容器线程调用此onTimeout方法。它可以调用setResult或setErrorResult来恢复处理

  • 另一个执行“停止”服务的线程

  • 如果在stop()服务期间调用的分派处理获得“延迟”锁,它将等待tomcat锁(比如TomcatLock)完成分派
    如果另一个执行超时处理的线程已经获取了TomcatLock,那么该线程将等待获取“deferred”上的锁以完成setResult()


    所以,我们最终陷入了一个典型的僵局状态

    当DeferredResult被认为是提供异步响应的另一种方式时,对方法上的synchronized不太在意。告诉一个方法它是同步的假设是同步的行为,如果不小心的话会导致死锁。
    synchronized
    s是我原始代码的残余。为了确定这一点,我将它们移除并重新测试。它没有改变任何东西。我在上游报告了这个错误,这个错误已经在Spring3.2.3中修复。