由於Spring的單態引起的執行緒阻塞的問題

iteye_1815發表於2008-09-13

 

執行緒阻塞的問題

關鍵字:Spring 單例,同步,執行緒阻塞,粒度

 

現象:某大型保險公司的OA應用(大集中模式,使用者有2萬多人,8千多個組織)在200多使用者線上時,竟然發生了weblogic例項掛起,分析dump檔案,發現有一個流程提交的執行緒發生意外,一直佔有著一個物件的鎖,因此它竟然阻塞了200多個執行緒,而所有的執行緒都阻塞在一個叫A的物件上,而這些被阻塞的執行緒還是處理不同的任務(就是說呼叫不同的方法),然後馬上去看A.java的程式碼,發現這個類的所有方法都加了synchronized關鍵字,即都進行了同步,程式碼示例如下:

public class AImpl{

 

         public void synchronized test1(){

 

}

 

public void synchronized test2(){

 

}

 

public void synchronized test3(){

 

}

}

 

public class BImpl{

         private A a;

public void setA(A a){

         this.a = a;

}

public void b_test1(){

                   a.test1();

}

 

pubic void b_test2(){

         a.test2();

}

 

public void b_test3(){

         a.test3();

}

}

 

問題出來了,有一個執行緒在執行b_test1()方法,而執行緒2在執行b_test2()方法,執行緒3在執行b_test3()方法,結果後面2個執行緒都被執行緒1阻塞了,等待它釋放持有的a物件的這把鎖,為什麼會這樣呢?而看AImpl.java這個類,其實作者的目的只是希望test1test2test3這三個方法在同一個時刻各自只有一個執行緒執行(即test1在同一個時刻只能有一個執行緒執行,其它要執行test1的執行緒只能排隊,而test1test2test3三個方法是可以併發執行的),但是真實的現象是:test1test2test3三個方法都在排對了!也就是說test2test3兩個方法都在等待物件a的鎖,而a的鎖被執行test1方法的執行緒所持有了,為什麼會這樣呢,單例!突然想到了Springbean在預設情況下都是單態的,也就是說a物件在整個虛擬機器都是唯一的!因此AImpl.java中的所有互不相干的方法都只能序列執行了!ohmy god

解決辦法:

1、  AImpl.java拆分,也就說把test1test2test3三個方法分拆到三個類中去,這樣就會有各自的例項,因此不再發生test1test2test3三個方法互相排隊的事情發生

2、  利用一個小技巧,即我們不動AImpl.java的程式碼,只是在Springxxx.bean.xml的配置檔案中,分別為test1test2test3三個方法配置三個例項就可以了(即a1a2a3),然後修改BImpl.java如下:

public class BImpl{

                   private A a1;

                   private A a2;

                   private A a3;

public void setA1(A a1){

         this.a1 = a1;

}

public void setA2(A a2){

         this.a2 = a2;

}

 

public void setA3(A a3){

         this.a3 = a3;

}

 

public void b_test1(){

                   a1.test1();

}

 

pubic void b_test2(){

         a2.test2();

}

 

public void b_test3(){

         a3.test3();

}

}

 

總結:解決問題的本質在於一定要明白synchronized關鍵字鎖住的是例項物件,因此問題的發生和解決都是基於它的

 

相關文章