`
snowfox2008
  • 浏览: 124659 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

由于Spring的单态引起的线程阻塞的问题

阅读更多

 

线程阻塞的问题

关键字: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关键字锁住的是实例对象,因此问题的发生和解决都是基于它的

 

分享到:
评论
2 楼 snowfox2008 2009-08-05  
kuaiyuelaogong 写道
兄弟,说一句,spring的单键只是在spring的容器内的单键,而非整个jvm的,就是说他的单键和传统的单键是有区别的,传统单键无论是构造器私有化还是枚举实现都是jvm级别的。

还有就是,你会这个问题只要搞三个锁不就行了吗,又不用改变原先类的方式也不需要才分类啊。

解决问题是不是有些经验欠佳啊^_^


呵呵,回复如下:
第一点,我看了Spring的文档,确实是我搞错了,它的单例是在当前上下文中唯一的,实际上是对于引用当前ID的bean来说是唯一的,在此因为此文的误导,给大家道歉。也十分感谢kuaiyuelaogong兄的指正。

第二点,我给出了2个方案,第二个方案就是不用改变原先类的方式,只需要让Spring创建三个实例就可以了。其实这一点也正式对第一点的一个印证。



1 楼 kuaiyuelaogong 2009-07-31  
兄弟,说一句,spring的单键只是在spring的容器内的单键,而非整个jvm的,就是说他的单键和传统的单键是有区别的,传统单键无论是构造器私有化还是枚举实现都是jvm级别的。

还有就是,你会这个问题只要搞三个锁不就行了吗,又不用改变原先类的方式也不需要才分类啊。

解决问题是不是有些经验欠佳啊^_^

相关推荐

Global site tag (gtag.js) - Google Analytics