当客户端关闭连接时,Spring StreamingResponseBody请求线程未清除

我在Controller中有一个端点,它返回StreamingResponseBody ,用于将文件发送到客户端。 这个代码大致如下:

 @RestController @RequestMapping(value="api") public class Controller { static class GetContentResponse implements StreamingResponseBody { @Override public void writeTo(OutputStream outputStream) throws IOException { while (!finished) { try { byte[] chunk = ; outputStream.write(chunk); } catch (InterruptedException e) { throw new RuntimeException("Interrupted!", e); } } outputStream.close(); } } @RequestMapping(value = "/{id}", method = RequestMethod.GET) public ResponseEntity get(@PathVariable(value = "id") String id) throws FaultResponse, InterruptedException { GetContentResponse getContentResponse = new GetContentResponse(); HttpHeaders header = new HttpHeaders(); return new ResponseEntity(getContentResponse, header, HttpStatus.OK); } } 

我通过以下方式设置异步请求的超时:

 @Configuration public class AsyncConfiguration extends WebMvcConfigurerAdapter { @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { configurer.setDefaultTimeout(5000); } } 

如果客户端取消请求,则响应的线程挂起,不会超时并且不会被清除。 该线程的堆栈跟踪是:

 Name: MvcAsync9 State: TIMED_WAITING on java.util.concurrent.CountDownLatch$Sync@4c51a108 Total blocked: 1 Total waited: 31 Stack trace: sun.misc.Unsafe.park(Native Method) java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215) java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos(AbstractQueuedSynchronizer.java:1037) java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(AbstractQueuedSynchronizer.java:1328) java.util.concurrent.CountDownLatch.await(CountDownLatch.java:277) org.apache.tomcat.util.net.NioEndpoint$KeyAttachment.awaitLatch(NioEndpoint.java:1361) org.apache.tomcat.util.net.NioEndpoint$KeyAttachment.awaitWriteLatch(NioEndpoint.java:1364) org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:114) org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:172) org.apache.coyote.http11.InternalNioOutputBuffer.writeToSocket(InternalNioOutputBuffer.java:139) - locked org.apache.coyote.http11.InternalNioOutputBuffer@62f2053a org.apache.coyote.http11.InternalNioOutputBuffer.addToBB(InternalNioOutputBuffer.java:197) - locked org.apache.coyote.http11.InternalNioOutputBuffer@62f2053a org.apache.coyote.http11.InternalNioOutputBuffer.access$000(InternalNioOutputBuffer.java:41) org.apache.coyote.http11.InternalNioOutputBuffer$SocketOutputBuffer.doWrite(InternalNioOutputBuffer.java:320) org.apache.coyote.http11.filters.IdentityOutputFilter.doWrite(IdentityOutputFilter.java:84) org.apache.coyote.http11.AbstractOutputBuffer.doWrite(AbstractOutputBuffer.java:256) org.apache.coyote.Response.doWrite(Response.java:501) org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:388) org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:344) org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:418) org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:406) org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:97) org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:90) org.springframework.security.web.context.OnCommittedResponseWrapper$SaveContextServletOutputStream.write(OnCommittedResponseWrapper.java:537) com.mackie.test.Controller$GetContentResponse.writeTo(Controller.java:98) org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler$StreamingResponseBodyTask.call(StreamingResponseBodyReturnValueHandler.java:108) org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler$StreamingResponseBodyTask.call(StreamingResponseBodyReturnValueHandler.java:94) org.springframework.web.context.request.async.WebAsyncManager$4.run(WebAsyncManager.java:316) java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) java.util.concurrent.FutureTask.run(FutureTask.java:266) java.lang.Thread.run(Thread.java:745) 

当客户端断开连接时,如何确保线程被正确销毁?

我自己发现了问题:服务器和客户端之间有一个代理,它没有正确地中断连接。 没有代理一切正常。