当JBOSS在部署应用时,遇到System.exit()方法调用,会产生死锁。
我们先来看看死锁时的线程快照:
“JBoss Shutdown Hook” daemon prio=10 tid=0x0000000056fa8000 nid=0x2525 waiting for monitor entry [0x0000000047184000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.jboss.web.AbstractWebContainer.stop(AbstractWebContainer.java:494)
- waiting to lock <0x00000000c16bc538> (a org.jboss.web.tomcat.service.JBossWeb)
… …
at org.jboss.deployment.MainDeployer.stop(MainDeployer.java:667)
at org.jboss.deployment.MainDeployer.undeploy(MainDeployer.java:638)
at org.jboss.deployment.MainDeployer.shutdown(MainDeployer.java:516)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
at org.jboss.system.server.ServerImpl$ShutdownHook.shutdownDeployments(ServerImpl.java:1058)
at org.jboss.system.server.ServerImpl$ShutdownHook.shutdown(ServerImpl.java:1033)
at org.jboss.system.server.ServerImpl$ShutdownHook.run(ServerImpl.java:996)
“main” prio=10 tid=0x00000000550b3000 nid=0x2481 in Object.wait() [0x000000004232f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000c020b250> (a org.jboss.system.server.ServerImpl$ShutdownHook)
at java.lang.Thread.join(Thread.java:1186)
- locked <0x00000000c020b250> (a org.jboss.system.server.ServerImpl$ShutdownHook)
at java.lang.Thread.join(Thread.java:1239)
at java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:79)
at java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:24)
at java.lang.Shutdown.runHooks(Shutdown.java:79)
at java.lang.Shutdown.sequence(Shutdown.java:123)
at java.lang.Shutdown.exit(Shutdown.java:168)
- locked <0x00000000b05864d8> (a java.lang.Class for java.lang.Shutdown)
at java.lang.Runtime.exit(Runtime.java:90)
at java.lang.System.exit(System.java:904)
at com.taobao.matrix.galaxy.common.failover.config.ConfigManager.registerWithDiamond(ConfigManager.java:246)
at com.taobao.matrix.galaxy.common.failover.config.ConfigManager.afterPropertiesSet(ConfigManager.java:97)
… …
at org.jboss.web.AbstractWebContainer.start(AbstractWebContainer.java:466)
- locked <0x00000000c16bc538> (a org.jboss.web.tomcat.service.JBossWeb)
… …
at org.jboss.deployment.MainDeployer.start(MainDeployer.java:1025)
at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:819)
… …
at org.jboss.Main.boot(Main.java:200)
at org.jboss.Main$1.run(Main.java:508)
at java.lang.Thread.run(Thread.java:662)
这里涉及到两个线程,主线程main和JBOSS的shutdown hook线程。
main线程在部署应用时,首先会获得org.jboss.web.tomcat.service.JBossWeb类的对象的锁,在获得锁后,遇到System.exit()调用,JVM会在System.exit()中调用所有注册过的shutdown hook,其中也包括JBOSS的shutdown hook,main线程会等待所有的shutdown hook执行完毕后,再恢复自身的执行,关闭虚拟机。
JBOSS的shutdown hook的行为是关闭JBOSS,在关闭之前先卸载所有部署于JBOSS的应用,卸载应用时又会尝试获取org.jboss.web.tomcat.service.JBossWeb类的对象的锁,但这个锁被main线程占有,没有释放,导致JBOSS的shutdown hook线程挂起。
此时的状态是,main线程等待shutdown hook执行完毕,shutdown hook等待main线程占有的锁,产生死锁。
本文来源于"阿里中间件团队播客",原文发表时间" 2011-11-22"