Poke-a-Dot (Provider)
Naive approach: use StringUtils.repeat (source) without the ThreadLocal:


public static String repeat(final char ch, final int repeat) {
    final char[] buf = new char[repeat];
    for (int i = repeat - 1; i &gt;= 0; i--) {
        buf[i] = ch;
    }
    return new String(buf);
}



Anyway, I suppose you did some profiling and it turned out that this is a bottleneck. Otherwise I'd really not complicate it with the ThreadLocal nor the doubling/concatenation logic.
substring in Java 6 used the same character array as the original String instance but it was changed in Java 7. So, substring calls copies the character array anyway, therefore string doubling and calling substring does not seem beneficial to me. (Anyway, it should be measured.)

There is one exception (according to the source which Eclipse brings up for Java 8) when beginIndex is zero and endIndex is the length of the original string. In this case substring returns the same String instance without copying. This case seems unlikely here, I guess there's a little chance that PAD_BASE.lenght will be the same as the length parameter since the while loop doubles the size of the padding string on every iteration.

So, in an average case the naive approach would create less new String (and underlying char[]) objects here than the one with substring.
Another idea is storing an array of strings in the ThreadLocal and extending the array on demand if the required lenght is longer than paddings.lenght:

String paddings[] = new String[max];
for (int i = 0; i &lt; max; i++) {
    paddings[i] = StringUtils.repeat('.', i);
}

2 could be a named constant.