使用StringBuilder的Java CLI应用程序性能

时间:2010-08-04 20:38:26

标签: java stringbuilder performance

常规
我正在编写一个套接字客户端,它从一些服务器端(远程的)接收“市场”数据/引用(永不结束循环)。
我正在将数据分成块,以便我可以使用它 每个块包含大约200个字符,需要转换为数组 分块后,它被解析为List(这里没有问题)。

问题:
运行10分钟后CPU使用率达到40% 我设法解决了这个问题 每个块都需要转换为json 所以我现在给你解决问题的实际代码 此代码每300-400 MS执行一次 跳过此代码将使整个系统的CPU使用率降低1%-2%。

注意:
我已经读过这个帖子,但我没有看到任何解决方案 Is it better to reuse a StringBuilder in a loop?

代码:

private static StringBuffer jsonVal = new StringBuffer();

    public static String toJson(List<QuotesData> quotesData) {
        // Empty variable
        jsonVal.delete(0, jsonVal.length());
        jsonVal.append("{");
        synchronized (quotesData) {
            for (QuotesData quote : quotesData) {

                jsonVal.append("\"").append(quote.getSymbol()).append("\":[{");
                jsonVal.append("\"ask\":\"").append(quote.getAsk()).append(
                        "\",");
                jsonVal.append("\"bid\":\"").append(quote.getBid()).append(
                        "\",");
                jsonVal.append("\"time\":\"").append(quote.getDateTime())
                        .append("\"}],");

            }
            jsonVal.append("}");
            String returnString = jsonVal.toString();
            return returnString.toString().replace("}],}", "}]}");
        }
    }

4 个答案:

答案 0 :(得分:2)

首先,我建议使用JDK6中包含的JProfiler或JConsole来精确地确定 的性能。

在不知道CPU使用情况的地方,我会避免使用synchronized。我怀疑append是个问题。通过摆脱static本地jsonVal来清理它。

public static String toJson(final List<QuotesData> quotesData) {
    final List<QuotesData> theData = new ArrayList<QuotesData>(quotesData);
    StringBuffer jsonVal = new StringBuffer();
    jsonVal.append("{");
    for (QuotesData quote : quotesData) {
        jsonVal.append("\"").append(quote.getSymbol()).append("\":[{");
        jsonVal.append("\"ask\":\"").append(quote.getAsk()).append(
                "\",");
        jsonVal.append("\"bid\":\"").append(quote.getBid()).append(
                "\",");
        jsonVal.append("\"time\":\"").append(quote.getDateTime())
               .append("\"}],");

    }
    jsonVal.append("}");
    String returnString = jsonVal.toString();
    return returnString.toString().replace("}],}", "}]}");
}

考虑使用像Gson这样的JSON库。代码变得更加简单。如果需要,您可以调整输出:

private static final Gson gson = new Gson();
public static String toJson(final List<QuotesData> quotesData) {
    return gson.toJson(new ArrayList<QuoteData>(quotesData));
}

答案 1 :(得分:0)

一些建议:

  • 描述代码,它应该显示热点。
  • 使用StringBuilder代替StringBufferStringBuffer已同步,StringBuilder未同步。
  • 真的需要synchronized声明吗?如果没有,请尝试将其删除。
  • return语句中不需要
  • toString()。你可以删除它。
  • 修改代码,以便最后不需要replace()方法,如果returnString很长,则代价可能会很高。
  • 尝试在循环之前创建一个新的StringBuffer对象,而不是清除旧的。{/ li>
  • 尝试返回字符串的interned值,即return returnString.intern()

答案 2 :(得分:0)

我的客人是StringBuilder不断调整大小。有多少引号数据?我建议你在for循环之前创建一个大小的StringBuilder:

StringBuffer jsonVal = new StringBuffer(quotesData.size()*200); //the 200 is on top of my head. Do a few loop to see what is the average length of a QuotesData.

顺便问一下,您是否考虑过使用StringBuilder?它与StringBuffer相同,减去线程安全的开销(StringBuffer是同步的,StringBuild不是)。

答案 3 :(得分:0)

好的,所以这看起来像过度优化的经典案例。 对象创建并不需要重写相同的字符串缓冲区,特别是如果每​​3到400毫秒调用一次。

我会尝试解决所有可能的情况: 指数增长 上面的代码每300毫秒分配给一个新的线程,但是列表很大,需要300多秒才能序列化。如果是这种情况,您基本上会窒息资源,应用程序崩溃只是时间问题。 如果是这种情况,您应该看到CPU不断上升。 解决方案是:

  1. 限制可以并发运行的线程数,这样就不会终止应用程序
  2. 同时构建json对象并合并结果,因此构建单个json所需的时间少于300ms。
  3. <强>加速比 好的,所以列表不是克隆的,我假设它意味着它不是真正的列表,而是某种实现为列表接口的队列。所以保持同步,我会这样做:

    public static final int JSON_LENGTH = 250; //you probably know this
    
    public static String toJson(final List<QuotesData> quotesData) {
        jsonVal = new StringBuilder(JSON_LENGTH * quotesData.size());
        jsonVal.append("{");
        synchronized (quotesData) {
            for (QuotesData quote : quotesData) {
    
                jsonVal.append("\"").append(quote.getSymbol()).append("\":[{")
                .append("\"ask\":\"").append(quote.getAsk()).append("\",")
                .append("\"bid\":\"").append(quote.getBid()).append("\",")
                .append("\"time\":\"").append(quote.getDateTime()).append("\"}],");
    
            }
            // much much faster than replace
            jsonVal.setCharAt(jsonVal.length()-1, '}');
            return jsonVal.toString();
        }
    }
    

    大多数变化都是装饰性的,我很确定JIT已经对它们进行了优化。我唯一的区别是使用StringBuilder并每次创建一个新的,不要使用 .replace()。 但要进一步强调我的观点,除非你符合第一个描述(指数增长),我怀疑问题在这里。我先看看你的列表实现。