当JBOSS在部署应用时,遇到System.exit()方法调用,会产生死锁。
我们先来看看死锁时的线程快照:
“JBossShutdownHook”daemonprio=10tid=0x0000000056fa8000nid=0×2525waitingformonitorentry[0x0000000047184000]
java.lang.Thread.State:BLOCKED(onobjectmonitor)
atorg.jboss.web.AbstractWebContainer.stop(AbstractWebContainer.java:494)
-waitingtolock<0x00000000c16bc538>(aorg.jboss.web.tomcat.service.JBossWeb)
……
atorg.jboss.deployment.MainDeployer.stop(MainDeployer.java:667)
atorg.jboss.deployment.MainDeployer.undeploy(MainDeployer.java:638)
atorg.jboss.deployment.MainDeployer.shutdown(MainDeployer.java:516)
atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)
atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
atjava.lang.reflect.Method.invoke(Method.java:597)
atorg.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
atorg.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
atorg.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
atorg.jboss.mx.server.Invocation.invoke(Invocation.java:88)
atorg.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
atorg.jboss.mx.server.Invocation.invoke(Invocation.java:88)
atorg.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
atorg.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
atorg.jboss.system.server.ServerImpl$ShutdownHook.shutdownDeployments(ServerImpl.java:1058)
atorg.jboss.system.server.ServerImpl$ShutdownHook.shutdown(ServerImpl.java:1033)
atorg.jboss.system.server.ServerImpl$ShutdownHook.run(ServerImpl.java:996)
“main”prio=10tid=0x00000000550b3000nid=0×2481inObject.wait()[0x000000004232f000]
java.lang.Thread.State:WAITING(onobjectmonitor)
atjava.lang.Object.wait(NativeMethod)
-waitingon<0x00000000c020b250>(aorg.jboss.system.server.ServerImpl$ShutdownHook)
atjava.lang.Thread.join(Thread.java:1186)
-locked<0x00000000c020b250>(aorg.jboss.system.server.ServerImpl$ShutdownHook)
atjava.lang.Thread.join(Thread.java:1239)
atjava.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:79)
atjava.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:24)
atjava.lang.Shutdown.runHooks(Shutdown.java:79)
atjava.lang.Shutdown.sequence(Shutdown.java:123)
atjava.lang.Shutdown.exit(Shutdown.java:168)
-locked<0x00000000b05864d8>(ajava.lang.Classforjava.lang.Shutdown)
atjava.lang.Runtime.exit(Runtime.java:90)
atjava.lang.System.exit(System.java:904)
atcom.taobao.matrix.galaxy.common.failover.config.ConfigManager.registerWithDiamond(ConfigManager.java:246)
atcom.taobao.matrix.galaxy.common.failover.config.ConfigManager.afterPropertiesSet(ConfigManager.java:97)
……
atorg.jboss.web.AbstractWebContainer.start(AbstractWebContainer.java:466)
-locked<0x00000000c16bc538>(aorg.jboss.web.tomcat.service.JBossWeb)
……
atorg.jboss.deployment.MainDeployer.start(MainDeployer.java:1025)
atorg.jboss.deployment.MainDeployer.deploy(MainDeployer.java:819)
……
atorg.jboss.Main.boot(Main.java:200)
atorg.jboss.Main$1.run(Main.java:508)
atjava.lang.Thread.run(Thread.java:662)
这里涉及到两个线程,主线程main和JBOSS的shutdownhook线程。
main线程在部署应用时,首先会获得org.jboss.web.tomcat.service.JBossWeb类的对象的锁,在获得锁后,遇到System.exit()调用,JVM会在System.exit()中调用所有注册过的shutdownhook,其中也包括JBOSS的shutdownhook,main线程会等待所有的shutdownhook执行完毕后,再恢复自身的执行,关闭虚拟机。
JBOSS的shutdownhook的行为是关闭JBOSS,在关闭之前先卸载所有部署于JBOSS的应用,卸载应用时又会尝试获取org.jboss.web.tomcat.service.JBossWeb类的对象的锁,但这个锁被main线程占有,没有释放,导致JBOSS的shutdownhook线程挂起。
此时的状态是,main线程等待shutdownhook执行完毕,shutdownhook等待main线程占有的锁,产生死锁。
阿里中间件博客 原文链接:http://jm-blog.aliapp.com/?p=1256