You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@struts.apache.org by "Davide Ruffolo (JIRA)" <ji...@apache.org> on 2018/03/14 08:47:03 UTC

[jira] [Commented] (WW-4817) Threads get blocked due to unnecessary synchronization in OgnlRuntime

    [ https://issues.apache.org/jira/browse/WW-4817?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16398274#comment-16398274 ] 

Davide Ruffolo commented on WW-4817:
------------------------------------

[~yasser.zamani], we have the bug too in the struts2 v2.3.34, invokeMethod method in OgnlRuntime class all threads except the first go to WAITING state.

Attached thredDump of the waiting threads.

Can you give me a feedback or a fix?

> Threads get blocked due to unnecessary synchronization in OgnlRuntime
> ---------------------------------------------------------------------
>
>                 Key: WW-4817
>                 URL: https://issues.apache.org/jira/browse/WW-4817
>             Project: Struts 2
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: 2.3.32, 2.5.12
>            Reporter: Santhana Preethi J
>            Assignee: Lukasz Lenart
>            Priority: Major
>             Fix For: 2.3.34, 2.5.13
>
>         Attachments: ThreadBlock.war, threadDump.txt
>
>
> In multi-threaded scenario, due to unnecessary synchronization in invokeMethod method in OgnlRuntime class all threads except the first go to BLOCKED state.
> {code:java}
> public static Object invokeMethod(Object target, Method method, Object[] argsArray)
>     throws InvocationTargetException, IllegalAccessException
>   { 
> .......
>  synchronized (method) {
>       if ((_methodAccessCache.get(method) == null) || (_methodAccessCache.get(method) == Boolean.TRUE))
>       {
>         syncInvoke = true;
>       }
> .......
>     }
> {code}
> Because *syncInvoke* becomes true for the first thread irrespective of whether the method is public or not, all other threads go to block state till the first thread leaves the method invocation synchronization block.
> Attached threadDump of the blocked threads waiting to lock the monitor 0x00000006c690e5b8 even though the method invoked by the action is public.
> {code:java}
> "_###_Thread-1499929571461_###_http-nio-8443-exec-20" #374 daemon prio=5 os_prio=0 tid=0x00007f830513a000 nid=0x49c1 waiting for monitor entry [0x00007f7e9c7c2000]
>    java.lang.Thread.State: BLOCKED (on object monitor)
> 	at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:826)
> 	- waiting to lock <0x00000006c690e5b8> (a java.lang.reflect.Method)
> 	at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1294)
> 	at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
> 	at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:117)
> 	at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:108)
> 	at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1370)
> 	at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
> 	at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
> 	at ognl.SimpleNode.getValue(SimpleNode.java:258)
> 	at ognl.Ognl.getValue(Ognl.java:467)
> 	at ognl.Ognl.getValue(Ognl.java:431)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil$3.execute(OgnlUtil.java:352)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil.compileAndExecuteMethod(OgnlUtil.java:404)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil.callMethod(OgnlUtil.java:350)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:430)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:290)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:251)
> 	at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:168)
> 	.........
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 	at java.lang.reflect.Method.invoke(Method.java:498)
> 	..........
> 	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
> 	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
> 	at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:240)
> 	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
> 	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502)
> 	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1132)
> 	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
> 	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1533)
> 	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1489)
> 	- locked <0x00000006c5249d98> (a org.apache.tomcat.util.net.NioChannel)
> 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
> 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
> 	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
> 	at java.lang.Thread.run(Thread.java:748)
> "Thread-1499929605769_###_Thread-1499929605766_###_http-nio-8443-exec-19" #373 daemon prio=5 os_prio=0 tid=0x00007f8305138000 nid=0x49c0 waiting for monitor entry [0x00007f7e9c8c3000]
>    java.lang.Thread.State: BLOCKED (on object monitor)
> 	at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:826)
> 	- waiting to lock <0x00000006c690e5b8> (a java.lang.reflect.Method)
> 	at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1294)
> 	at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
> 	at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:117)
> 	at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:108)
> 	at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1370)
> 	at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
> 	at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
> 	at ognl.SimpleNode.getValue(SimpleNode.java:258)
> 	at ognl.Ognl.getValue(Ognl.java:467)
> 	at ognl.Ognl.getValue(Ognl.java:431)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil$3.execute(OgnlUtil.java:352)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil.compileAndExecuteMethod(OgnlUtil.java:404)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil.callMethod(OgnlUtil.java:350)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:430)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:290)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:251)
> 	........
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 	at java.lang.reflect.Method.invoke(Method.java:498)
> 	.........
> 	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
> 	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
> 	at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:240)
> 	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
> 	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502)
> 	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1132)
> 	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
> 	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1533)
> 	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1489)
> 	- locked <0x00000006c844cea8> (a org.apache.tomcat.util.net.NioChannel)
> 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
> 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
> 	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
> 	at java.lang.Thread.run(Thread.java:748)
> "Thread-1499929651452_###_Thread-1499929651449_###_http-nio-8443-exec-17" #371 daemon prio=5 os_prio=0 tid=0x00007f8305134000 nid=0x49be waiting for monitor entry [0x00007f7e9cac4000]
>    java.lang.Thread.State: BLOCKED (on object monitor)
> 	at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:826)
> 	- waiting to lock <0x00000006c690e5b8> (a java.lang.reflect.Method)
> 	at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1294)
> 	at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
> 	at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:117)
> 	at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:108)
> 	at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1370)
> 	at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
> 	at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
> 	at ognl.SimpleNode.getValue(SimpleNode.java:258)
> 	at ognl.Ognl.getValue(Ognl.java:467)
> 	at ognl.Ognl.getValue(Ognl.java:431)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil$3.execute(OgnlUtil.java:352)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil.compileAndExecuteMethod(OgnlUtil.java:404)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil.callMethod(OgnlUtil.java:350)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:430)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:290)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:251)
> 	........
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 	at java.lang.reflect.Method.invoke(Method.java:498)
> 	.........
> 	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
> 	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
> 	at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:240)
> 	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
> 	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502)
> 	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1132)
> 	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
> 	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1533)
> 	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1489)
> 	- locked <0x00000006c8605150> (a org.apache.tomcat.util.net.NioChannel)
> 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
> 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
> 	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
> 	at java.lang.Thread.run(Thread.java:748)
> "Thread-1499929544435_###_Thread-1499929544432_###_http-nio-8443-exec-13" #367 daemon prio=5 os_prio=0 tid=0x00007f830512c800 nid=0x49ba runnable [0x00007f7e9cec6000]
>    java.lang.Thread.State: RUNNABLE
> 	at java.net.SocketInputStream.socketRead0(Native Method)
> 	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
> 	at java.net.SocketInputStream.read(SocketInputStream.java:171)
> 	at java.net.SocketInputStream.read(SocketInputStream.java:141)
> 	at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:114)
> 	at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:161)
> 	at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:189)
> 	- locked <0x00000006c7201d08> (a com.mysql.jdbc.util.ReadAheadInputStream)
> 	at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3014)
> 	at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3467)
> 	at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3456)
> 	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3997)
> 	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2468)
> 	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2629)
> 	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2713)
> 	- locked <0x00000006c6a0cdd0> (a com.mysql.jdbc.JDBC4Connection)
> 	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2663)
> 	at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1599)
> 	- locked <0x00000006c6a0cdd0> (a com.mysql.jdbc.JDBC4Connection)
> 	.........
> 	at sun.reflect.GeneratedMethodAccessor44.invoke(Unknown Source)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 	at java.lang.reflect.Method.invoke(Method.java:498)
> 	.........
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 	at java.lang.reflect.Method.invoke(Method.java:498)
> 	..........
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 	at java.lang.reflect.Method.invoke(Method.java:498)
> 	at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:871)
> 	- locked <0x00000006c690e5b8> (a java.lang.reflect.Method)
> 	at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1294)
> 	at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
> 	at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:117)
> 	at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:108)
> 	at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1370)
> 	at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
> 	at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
> 	at ognl.SimpleNode.getValue(SimpleNode.java:258)
> 	at ognl.Ognl.getValue(Ognl.java:467)
> 	at ognl.Ognl.getValue(Ognl.java:431)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil$3.execute(OgnlUtil.java:352)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil.compileAndExecuteMethod(OgnlUtil.java:404)
> 	at com.opensymphony.xwork2.ognl.OgnlUtil.callMethod(OgnlUtil.java:350)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:430)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:290)
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:251)
> 	..........
> 	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> 	at java.lang.reflect.Method.invoke(Method.java:498)
> 	...........
> 	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
> 	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
> 	at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:240)
> 	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
> 	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502)
> 	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1132)
> 	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
> 	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1533)
> 	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1489)
> 	- locked <0x00000006c52e67a8> (a org.apache.tomcat.util.net.NioChannel)
> 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
> 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
> 	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
> 	at java.lang.Thread.run(Thread.java:748)
> {code}
> Modified the syncInvoke checks to prevent this unnecessary blocking
> {code:java}
>  public static Object invokeMethod(Object target, Method method, Object[] argsArray)
>     throws InvocationTargetException, IllegalAccessException
>   {
>     boolean syncInvoke = false;
>     boolean checkPermission = false;
>     boolean wasAccessible = true;
>     synchronized (method) {
>       if ((_methodAccessCache.get(method) == null))
>       {
>         if ((!Modifier.isPublic(method.getModifiers())) || (!Modifier.isPublic(method.getDeclaringClass().getModifiers())))
>         {
>           if (!(wasAccessible = method.isAccessible()))
>           {
>              method.setAccessible(true);
>             _methodAccessCache.put(method, Boolean.TRUE);
>           }
>           else {
>             _methodAccessCache.put(method, Boolean.FALSE);
>           }
>         }
>         else {
>           _methodAccessCache.put(method, Boolean.FALSE);
>         }
>       }
>       if (_methodAccessCache.get(method) == Boolean.TRUE))
>       {
>         syncInvoke = true;
>       }
>       if (((_securityManager != null) && (_methodPermCache.get(method) == null)) || (_methodPermCache.get(method) == Boolean.FALSE))
>       {
>         checkPermission = true;
>       }
>     }
>     Object result;
>     if (syncInvoke)
>     {
>       synchronized (method)
>       {
>         if (checkPermission)
>         {
>           try
>           {
>             _securityManager.checkPermission(getPermission(method));
>             _methodPermCache.put(method, Boolean.TRUE);
>           } catch (SecurityException ex) {
>             _methodPermCache.put(method, Boolean.FALSE);
>             throw new IllegalAccessException("Method [" + method + "] cannot be accessed.");
>           }
>         }
>         Object result = method.invoke(target, argsArray);
>         if (!wasAccessible)
>         {
>           method.setAccessible(false);
>         }
>       }
>     }
>     else {
>       if (checkPermission)
>       {
>         try
>         {
>           _securityManager.checkPermission(getPermission(method));
>           _methodPermCache.put(method, Boolean.TRUE);
>         } catch (SecurityException ex) {
>           _methodPermCache.put(method, Boolean.FALSE);
>           throw new IllegalAccessException("Method [" + method + "] cannot be accessed.");
>         }
>       }
>       result = method.invoke(target, argsArray);
>     }
>     return result;
>   }
> {code}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)