现有的StringBuilder“智能”初始容量解决方案

时间:2012-12-21 09:06:42

标签: java stringbuilder

我有一个记录和跟踪相关代码,在整个代码中经常调用,特别是在打开跟踪时。 StringBuilder用于构建String。字符串具有合理的最大长度,我想大约数百个字符。

问题:现有的库是否可以执行以下操作:

// in reality, StringBuilder is final,
// would have to create delegated version instead,
// which is quite a big class because of all the append() overloads
public class SmarterBuilder extends StringBuilder {         

    private final AtomicInteger capRef;

    SmarterBuilder(AtomicInteger capRef) {
        int len = capRef.get(); 
        // optionally save memory with expense of worst-case resizes:
        // len = len * 3 / 4;
        super(len);
        this.capRef = capRef;
    }

    public syncCap() {
        // call when string is fully built
        int cap;
        do {
            cap = capRef.get();
            if (cap >= length()) break;
        } while (!capRef.compareAndSet(cap, length());
    }
}

为了利用这一点,我的与日志相关的类将具有一个具有适当范围的共享capRef变量。

(奖金问题:我很好奇,是否可以在没有循环的情况下进行syncCap()?)

动机:我知道StringBuilder的默认长度总是太少。我可以(并且目前确实)投入一个特殊的初始容量值100,这会导致在某些情况下调整大小,但并非总是如此。但是,我不喜欢源代码中的幻数,这个功能就是“优化一次,在每个项目中使用”。

2 个答案:

答案 0 :(得分:1)

确保您进行了性能测量,以确保您真正为额外的工作获得了一些好处。

作为StringBuilder类的替代方法,请考虑StringBuilderFactory。它可以提供两个静态方法,一个用于获取StringBuilder,另一个用于在完成构建字符串时调用。您可以将StringBuilder作为参数传递给它,它会记录长度。 getStringBuilder方法将使用其他方法记录的统计信息来选择初始大小。

有两种方法可以避免在syncCap中循环:

  1. 同步。
  2. 忽略失败。
  3. 在这种情况下忽略失败的论点是你只需要对实际长度进行随机抽样。如果另一个线程正在同时更新,那么无论如何您都会获得字符串长度的最新视图。

答案 1 :(得分:0)

您可以将每个字符串的字符串长度存储在统计数组中。运行你的应用程序,并在关机时取你的字符串长度的90%四分之一(排序所有str长度值,并取数组pos = sortedStrings.size()* 0,9

的长度值

这样你创建了一个初始字符串构建器大小,其中90%的字符串都适合。

<强>更新
该值可以是硬编码的(如java对ArrayList中的值10执行),或从配置文件中读取,或在测试阶段自动计算。但是四分位计算不是免费的,所以最好你运行你的项目一段时间,在SmartBuilder内动态测量90%的四分之一,不时输出90%的四分之一,然后更改属性文件以使用该值点。

通过这种方式,您可以获得每个项目的最佳结果 或者,如果您更进一步:让智能生成器不时在配置文件中更新该值。 但这一切都不值得努力,你只会对数百万条目的数据,如数字路线图等做到这一点。