dom4j在高并发下创建dom树性能差

接口在压测的时候发现并发量上去之后,tps并没有按预期的上升,于是在开发环境下用jprofiler进行监控,发现大量线程处于阻塞状态

线程阻塞信息如下:

可以看到阻塞都是由于SynchronizedMap.get方法造成

由于dom4j内部缓存QNameCache使用的是Collections.synchronizedMap

package org.dom4j.tree;

import org.dom4j.DocumentFactory;
import org.dom4j.Namespace;
import org.dom4j.QName;

import java.util.*;


public class QNameCache {
    protected Map<String, QName> noNamespaceCache = Collections.synchronizedMap(new WeakHashMap<String, QName>());

    protected Map<Namespace, Map<String, QName>> namespaceCache = Collections.synchronizedMap(new WeakHashMap<Namespace, Map<String, QName>>());


    public QNameCache(DocumentFactory documentFactory) {
        this.documentFactory = documentFactory;
    }


    public QName get(String name) {
        QName answer = null;

        if (name != null) {
            answer = noNamespaceCache.get(name);
        } else {
            name = "";
        }

        if (answer == null) {
            answer = createQName(name);
            answer.setDocumentFactory(documentFactory);
            noNamespaceCache.put(name, answer);
        }

        return answer;
    }


    public QName get(String name, Namespace namespace) {
        Map<String, QName> cache = getNamespaceCache(namespace);
        QName answer = null;

        if (name != null) {
            answer = cache.get(name);
        } else {
            name = "";
        }

        if (answer == null) {
            answer = createQName(name, namespace);
            answer.setDocumentFactory(documentFactory);
            cache.put(name, answer);
        }

        return answer;
    }

 
}

 

解决方案: 因为项目的使用场景xml节点是固定的,不会无限增加,所以采用ConcurrentHashMap替换synchronizedMap,,如果节点数不固定且会无限增加,那么不能使用ConcurrentHashMap,有可能会导致缓存数据不会被回收,造成OOM

DocumentFactory初始化的方式是通过类加载加载具体类,具体类可以以系统的变量指定 ,key:org.dom4j.factory



import org.dom4j.DocumentFactory;
import org.dom4j.QName;
import org.dom4j.tree.QNameCache;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


public class CustomQNameCache extends QNameCache {


    public CustomQNameCache() {
        this(null);
    }

    public CustomQNameCache(DocumentFactory documentFactory) {
        super(documentFactory);
        noNamespaceCache = new ConcurrentHashMap();
        namespaceCache = new ConcurrentHashMap();
    }

}


import org.dom4j.DocumentFactory;
import org.dom4j.tree.QNameCache;

public class CustomDocumentFactory extends DocumentFactory {

    @Override
    protected QNameCache createQNameCache() {
        return new CustomQNameCache(this);
    }

}


import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;



@SpringBootApplication()
@MapperScan("com.ttfund.trade.unpaid.dal.mapper")
@EnableCaching
@ServletComponentScan
public class WebApiApplication {
    public static void main(String[] args) {
        //dom4j解析时防止线程阻塞
        System.setProperty("org.dom4j.factory","com.ttfund.trade.unpaid.utility.xml.CustomDocumentFactory");
        SpringApplication.run(WebApiApplication.class, args);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值