单例模式与高并发

SpringMVC与struts2最大区别:SpringMVC使用单例、struts2使用原型(有可能struts2中对象使用后不销毁而只进行初始化变量再使用)
当某个单例对象中含有不具有并发性的对象(即并发会出错),为提高并发有三种方法:
1、线程绑定(只允许当前线程使用绑定对象)
2、创建对象池
3、加锁

单例与原型

单例在并发中可以有多个单例实例化对象。单例模式是只创建一个对象

单例:每个线程都需要使用实例化一个对象,但是对象的获取方式是不存在创建,存在直接使用。不安全是指一个线程修改了某个单例对象变量,而该对象不会销毁,会被其他线程使用从而造成该对象变量数据错误。
原型:每个线程直接创建自己使用的对象,使用完直接销毁。
单例是实例化不销毁被重复使用,原型使用后就销毁。所以避免单例对象使用中进行修改自身变量。

 


在单例对象中进行线程绑定对象,定义如下:

    private ThreadLocal<Digester> tl = new ThreadLocal<Digester>();
    public Digester getDigester() {
        Digester digester = (Digester) this.tl.get();
        if (null == digester) {
            digester = super.getDigester();
            this.tl.set(digester);
        }
        return digester;
    }

 

在单例对象使用时进行线程绑定一个对象,高并发时单例对象被大量创建,但每个单例只绑定了一个不支持并发的对象。


而在原型中高并下使用单例模式目的只创建一个对象:

publci class Singleton{
     private static Singleton instance = null;
     private Singleton(){}

     public static Singleton getInstance(){
            if(instance == null){
                   instance = new Singleton();
            }
            return instance;
    }
}

 


高并发下会创建多个对象,而目的是只要一个实例对象,所以需要加锁进行同步

publci class Singleton{
     private static Singleton instance = null;
     private Singleton(){}

     public static synchronized Singleton getInstance(){
            if(instance == null){
                   instance = new Singleton();
            }
            return instance;
    }
} 

 


上面方式很影响性能,所以采用下面方式:

publci class Singleton{
     private static Singleton instance = null;
     private Singleton(){}

     public static Singleton getInstance(){
            if(instance == null){
                   synchronized(Singleton.class){
                        if(instance == null)
                        instance = new Singleton();
                   }           
             }
            return instance;
    }
} 

 



做了单例模式在多线程条件下的性能测试,结果表明我的想法是正确的:试图用单例来换取性能是不可行的,并发量较小(一般小于200),单例没有任何性能优势,也就没有使用必要,并发量较大(超过500),单例会引起类资源的争用,实例化速度急剧降低。这个测试说明:weblogic的最大线程=EJB实例的最大实例数=EJB中成员类(也就是业务类)的最大实例数,这几个东西是一条线下来的,是有内在关系的。
 
测试结果数据:
    一 使用单例模式:
      并发数量:    需要EJB实例数量   需要业务类实例数量  业务类实例化时间平均毫秒数
        200               28               28                         1
        500               33               33                         51
    二 使用传统技术:
      并发数量:    需要EJB实例数量   需要业务类实例数量  业务类实例化时间平均毫秒数
        200               28               28                          1
        500               33               33                          1                 
    从以上结果可以看出:
    第一:在多线程下,使用传统技术实例化类,根本不存在性能问题;
    第二:在多线程下,使用单例模式实例化类,有比较严重的性能问题;

posted @ 2016-01-06 11:23  W&L  阅读(12207)  评论(4编辑  收藏  举报