Description
For AsyncContext usages, tomcat ensures the non container threads wait for the container thread to exit the execution (the one starting the async context) to avoid concurrency issue.
For cxf it means you can resume() in a user thread on an AsyncResponse while you execute AsyncResponseImpl.suspendContinuationIfNeeded().
This can lead to a lock preventing the request to complete.
Here is a sample thread:
"managed-thread-3@7750" daemon prio=5 tid=0x48 nid=NA waiting java.lang.Thread.State: WAITING blocks http-nio-24622-exec-3@7702 at java.lang.Object.wait(Object.java:-1) at java.lang.Object.wait(Object.java:502) at org.apache.coyote.AsyncStateMachine.pauseNonContainerThread(AsyncStateMachine.java:452) at org.apache.coyote.AsyncStateMachine.asyncDispatch(AsyncStateMachine.java:315) at org.apache.coyote.http11.Http11Processor.action(Http11Processor.java:858) at org.apache.coyote.Request.action(Request.java:390) at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:203) - locked <0x21ed> (a java.lang.Object) at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:171) at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:165) at org.apache.openejb.server.httpd.EEFilter$AsynContextWrapper.dispatch(EEFilter.java:171) at org.apache.cxf.transport.http.Servlet3ContinuationProvider$Servlet3Continuation.redispatch(Servlet3ContinuationProvider.java:125) at org.apache.cxf.transport.http.Servlet3ContinuationProvider$Servlet3Continuation.resume(Servlet3ContinuationProvider.java:131) at org.apache.cxf.jaxrs.impl.AsyncResponseImpl.doResumeFinal(AsyncResponseImpl.java:96) - locked <0x2196> (a org.apache.cxf.jaxrs.impl.AsyncResponseImpl) at org.apache.cxf.jaxrs.impl.AsyncResponseImpl.doResume(AsyncResponseImpl.java:89) at org.apache.cxf.jaxrs.impl.AsyncResponseImpl.resume(AsyncResponseImpl.java:73) at com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor.lambda$async$0(AsyncInterceptor.java:63) at com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$$Lambda$55.375198754.run(Unknown Source:-1) at com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$TransactionProvider.run(AsyncInterceptor.java:148) at sun.reflect.GeneratedMethodAccessor95.invoke(Unknown Source:-1) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.webbeans.intercept.AbstractInvocationContext.directProceed(AbstractInvocationContext.java:113) at org.apache.webbeans.intercept.AbstractInvocationContext.proceed(AbstractInvocationContext.java:106) at org.apache.webbeans.intercept.InterceptorInvocationContext.proceed(InterceptorInvocationContext.java:67) at org.apache.openejb.cdi.transactional.InterceptorBase.intercept(InterceptorBase.java:66) at org.apache.openejb.cdi.transactional.RequiredInterceptor.intercept(RequiredInterceptor.java:35) at sun.reflect.GeneratedMethodAccessor85.invoke(Unknown Source:-1) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.webbeans.component.InterceptorBean.intercept(InterceptorBean.java:136) at org.apache.webbeans.intercept.InterceptorInvocationContext.proceed(InterceptorInvocationContext.java:63) at org.apache.webbeans.intercept.DefaultInterceptorHandler.invoke(DefaultInterceptorHandler.java:139) at com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$TransactionProvider$$OwbInterceptProxy0.run(com/github/rmannibucau/rblog/jaxrs/async/AsyncInterceptor$TransactionProvider.java:-1) at com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$TransactionProvider$$OwbNormalScopeProxy0.run(com/github/rmannibucau/rblog/jaxrs/async/AsyncInterceptor$TransactionProvider.java:-1) at com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$Metas.lambda$runInTransaction$6(AsyncInterceptor.java:130) at com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$Metas$$Lambda$56.1727885795.run(Unknown Source:-1) at com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$Metas.lambda$toJaxRs$7(AsyncInterceptor.java:136) at com.github.rmannibucau.rblog.jaxrs.async.AsyncInterceptor$Metas$$Lambda$57.1956863343.run(Unknown Source:-1) at org.apache.openejb.threads.task.CURunnable$1.call(CURunnable.java:35) at org.apache.openejb.threads.task.CURunnable$1.call(CURunnable.java:32) at org.apache.openejb.threads.task.CUTask.invoke(CUTask.java:89) at org.apache.openejb.threads.task.CURunnable.run(CURunnable.java:32) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) "http-nio-24622-exec-3@7702" daemon prio=5 tid=0x41 nid=NA waiting for monitor entry java.lang.Thread.State: BLOCKED waiting for managed-thread-3@7750 to release lock on <0x2196> (a org.apache.cxf.jaxrs.impl.AsyncResponseImpl) at org.apache.cxf.jaxrs.impl.AsyncResponseImpl.suspendContinuationIfNeeded(AsyncResponseImpl.java:263) at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:191)
Solution would be to not synchronize both method and probably move to a volatile state
Attachments
Issue Links
- is duplicated by
-
CXF-6249 Investigate if resuming AsyncContext on the invocation thread works
- Closed