当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