在Weblogic中,我們通常能看到像下面這樣的警告信息:
BEA-000337 Feb 1, 2007 11:01:05 AM EST Error WebLogicServer ExecuteThread: '14' for queue: 'weblogic.kernel.Default' has been busy for "72" seconds working on the request "connection82.session95", which is more than the configured time (StuckThreadMaxTime) of "60" seconds.
這樣的信息只是一個提示,告訴最終用戶某個執(zhí)行線程執(zhí)行了多長時間(只有執(zhí)行時間超過StuckThread-MaxTime,默認(rèn)600秒),用戶可以根據(jù)這些信息,分析對應(yīng)的請求執(zhí)行了這么長時間是否正常,如果在預(yù)期或可以接受范圍內(nèi),不用作任何干預(yù),否則我們需要借助于thread dump分析執(zhí)行時間的瓶頸。出現(xiàn)這樣的警告信息,weblogic不會對這樣的線程作任何操作(weblogic無法識別這么長的執(zhí)行時間是不是用戶所預(yù)期的,比如報表操作、文件傳輸?shù)缺旧砜赡芫秃芎臅r),直到線程結(jié)束。線程能執(zhí)行結(jié)束還好,如果是死鎖呢? 這樣的線程會一直被掛著,直到weblogic重啟。重啟對于很多生產(chǎn)系統(tǒng)而言是最后的選擇,那么我們有什么方法來避免重啟呢? Weblogic9以后,線程管理方面work manager代替了早期的thread pool,而且work manager提供了stuck thread的管理,比如出現(xiàn)幾個stuck thread后,我們可以要求work manager停止應(yīng)用,避免更多的線程被stuck。weblogic停止應(yīng)用只是不提供服務(wù),但還是不會影響正在執(zhí)行的線程。
曾經(jīng)不止一次的被客戶問道我們能否中斷這樣的線程,從weblogic層面來看,這是mission impossible。現(xiàn)在有了TI,我們可以通過它中斷這樣的線程。
要中斷這樣的線程,首先要借助thread dump拿到線程名,我們將以線程名為filter。Thread dump信息如下:
"[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'" daemon prio=6 tid=0x2b25a800 nid=0x3c0 waiting on condition [0x2e08f000..0x2e08fa14]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
......
上面這個線程的名字就是:[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'
為了能正確的attach上JVM,啟動的時候需要加上如下的JAVA_OPTIONS,
-Xdebug -Xrunjdwp:transport=dt_socket,address=9191,server=y,suspend=n
現(xiàn)在我們就可以下面的方法attach到target JVM,
1 private VirtualMachine connectVM(){
2 VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
3 List connectors = vmm.attachingConnectors();
4 Connector conn = null;
5 AttachingConnector socketAttachingConnector = null;
6 /*
7 * host and port should be set here
8 */
9
.
10 try{
11 vm = socketAttachingConnector.attach(arguments);
12 }catch(Exception e){
13 e.printStackTrace();
14 }
15 return this.vm;
16 }
2 VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
3 List connectors = vmm.attachingConnectors();
4 Connector conn = null;
5 AttachingConnector socketAttachingConnector = null;
6 /*
7 * host and port should be set here
8 */
9

10 try{
11 vm = socketAttachingConnector.attach(arguments);
12 }catch(Exception e){
13 e.printStackTrace();
14 }
15 return this.vm;
16 }
有了線程名、connection,我們就可以用下面的方法去中斷掛死線程了,
1 public void terminateThread(String threadPattern){
2 if(vm != null){
3 List threads = vm.allThreads();
4 ThreadReference tr = null;
5 int loop = -1;
6 for(loop=0; loop<threads.size(); loop++){
7 if(tr.toString().indexOf(threadPattern) != -1){
8 tr.interrupt();
9 System.out.println(threadPattern + " is terminated!");
10 break;
11 }
12 }
13 if(loop == threads.size())
14 System.out.println("no matched thread was found in target VM!");
15 }
16 }
2 if(vm != null){
3 List threads = vm.allThreads();
4 ThreadReference tr = null;
5 int loop = -1;
6 for(loop=0; loop<threads.size(); loop++){
7 if(tr.toString().indexOf(threadPattern) != -1){
8 tr.interrupt();
9 System.out.println(threadPattern + " is terminated!");
10 break;
11 }
12 }
13 if(loop == threads.size())
14 System.out.println("no matched thread was found in target VM!");
15 }
16 }
線程被中斷的時候,會收到InterruptedExcetpion,比如我在測試中讓線程sleep,然后利用上面的程序去中斷sleep,收到的異常如下:
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at test.jpda.clazz.Test2.run(Test2.java:14)
at test.jpda.clazz.Test1.run(Test1.java:10)
at test.jpda.clazz.Test.run(Test.java:9)
at jsp_servlet.__index._jspService(__index.java:91)
at weblogic.servlet.jsp.JspBase.service(JspBase.java:34)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.ru(WebAppServletContext.java:3498)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(Unknown Source)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2180)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2086)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1406)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)
注意:線程名一定不能寫錯啊,否則就可能誤殺了,老板批你別怨俺。