$ ab -n 10000 -c 200 http://localhost:8080/async This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/
Server Software: Apache-Coyote/1.1 Server Hostname: localhost Server Port: 8080
Document Path: /async Document Length: 40 bytes
Concurrency Level: 200 Time taken for tests: 1000.284 seconds Complete requests: 10000 Failed requests: 47 (Connect: 0, Receive: 0, Length: 47, Exceptions: 0) Write errors: 0 Non-2xx responses: 47 Total transferred: 1530740 bytes HTML transferred: 506980 bytes Requests per second: 10.00 [#/sec] (mean) Time per request: 20005.686 [ms] (mean) Time per request: 100.028 [ms] (mean, across all concurrent requests) Transfer rate: 1.49 [Kbytes/sec] received
Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 5.0 0 501 Processing: 2 19810 1683.3 20001 20560 Waiting: 1 19810 1683.4 20000 20558 Total: 2 19811 1683.0 20001 20560
Percentage of the requests served within a certain time (ms) 50% 20001 66% 20001 75% 20002 80% 20002 90% 20004 95% 20009 98% 20020 99% 20035 100% 20560 (longest request)
一月 21, 2017 1:05:32 上午 org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() for servlet [com.air.async.AsyncServlet] in context with path [] threw exception java.util.concurrent.RejectedExecutionException: Task com.air.async.AsyncRequestProcessor@3caec762 rejected from java.util.concurrent.ThreadPoolExecutor@64db0f23[Running, pool size = 100, active threads = 100, queued tasks = 100, completed tasks = 9726] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048) at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821) at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372) at com.air.async.AsyncServlet.doGet(AsyncServlet.java:25) at javax.servlet.http.HttpServlet.service(HttpServlet.java:621) at javax.servlet.http.HttpServlet.service(HttpServlet.java:728) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603) at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2430) at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2419) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745)
$ ab -n 10000 -c 200 http://localhost:8080/hello This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/
Server Software: Apache-Coyote/1.1 Server Hostname: localhost Server Port: 8080
Document Path: /hello Document Length: 12 bytes
Concurrency Level: 200 Time taken for tests: 2002.151 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 1340000 bytes HTML transferred: 120000 bytes Requests per second: 4.99 [#/sec] (mean) Time per request: 40043.028 [ms] (mean) Time per request: 200.215 [ms] (mean, across all concurrent requests) Transfer rate: 0.65 [Kbytes/sec] received
Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.4 0 8 Processing: 10002 39740 2686.3 40005 50319 Waiting: 10002 39740 2686.4 40004 50319 Total: 10002 39741 2686.3 40005 50319
Percentage of the requests served within a certain time (ms) 50% 40005 66% 40009 75% 40014 80% 40022 90% 40122 95% 40316 98% 40449 99% 40483 100% 50319 (longest request)
privatestaticfinal ResponseEntity<Map<String, String>> NOT_MODIFIED_RESPONSE_LIST = new ResponseEntity<>(HttpStatus.NOT_MODIFIED); final DeferredResult<ResponseEntity<Map<String, String>>> deferredResult = new DeferredResult<>(90000L, NOT_MODIFIED_RESPONSE_LIST);
publicvoidstartCallableProcessing(Callable<?> callable, Object... processingContext)throws Exception { Assert.notNull(callable, "Callable must not be null"); startCallableProcessing(new WebAsyncTask(callable), processingContext); }
publicvoidstartCallableProcessing(final WebAsyncTask<?> webAsyncTask, Object... processingContext)throws Exception { Assert.notNull(webAsyncTask, "WebAsyncTask must not be null"); Assert.state(this.asyncWebRequest != null, "AsyncWebRequest must not be null");
//超时 Long timeout = webAsyncTask.getTimeout(); if (timeout != null) { this.asyncWebRequest.setTimeout(timeout); } //线程池 AsyncTaskExecutor executor = webAsyncTask.getExecutor(); if (executor != null) { this.taskExecutor = executor; } //拦截器 List<CallableProcessingInterceptor> interceptors = new ArrayList<CallableProcessingInterceptor>(); interceptors.add(webAsyncTask.getInterceptor()); interceptors.addAll(this.callableInterceptors.values()); interceptors.add(timeoutCallableInterceptor);
final Callable<?> callable = webAsyncTask.getCallable(); final CallableInterceptorChain interceptorChain = new CallableInterceptorChain(interceptors);
privatebooleansetResultInternal(Object result){ // Immediate expiration check outside of the result lock if (isSetOrExpired()) { returnfalse; } DeferredResultHandler resultHandlerToUse; synchronized (this) { // Got the lock in the meantime: double-check expiration status if (isSetOrExpired()) { returnfalse; } // At this point, we got a new result to process this.result = result; resultHandlerToUse = this.resultHandler; if (resultHandlerToUse == null) { // No result handler set yet -> let the setResultHandler implementation // pick up the result object and invoke the result handler for it. returntrue; } // Result handler available -> let's clear the stored reference since // we don't need it anymore. this.resultHandler = null; } // If we get here, we need to process an existing result object immediately. // The decision is made within the result lock; just the handle call outside // of it, avoiding any deadlock potential with Servlet container locks. resultHandlerToUse.handleResult(result); returntrue; }