Статьи

Можно ли оптимизировать синхронизацию?

обзор

Существует распространенное заблуждение, что поскольку JIT является разумным, и синхронизация может быть исключена для объекта, который является только локальным для метода, который не оказывает влияния на производительность.

Тест, сравнивающий StringBuffer и StringBuilder

Эти два класса делают в основном одно и то же, за исключением того, что один синхронизируется (StringBuffer), а другой — нет. Это также класс, который часто используется в одном методе для создания строки. В следующем тесте делается попытка определить, какую разницу могут использовать друг друга.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
static String dontOptimiseAway = null;
static String[] words = new String[100000];
 
public static void main(String... args) {
    for (int i = 0; i < words.length; i++)
        words[i] = Integer.toString(i);
 
    for (int i = 0; i < 10; i++) {
        dontOptimiseAway = testStringBuffer();
        dontOptimiseAway = testStringBuilder();
    }
}
 
private static String testStringBuffer() {
    long start = System.nanoTime();
    StringBuffer sb = new StringBuffer();
    for (String word : words) {
        sb.append(word).append(',');
    }
    String s = sb.substring(0, sb.length() - 1);
    long time = System.nanoTime() - start;
    System.out.printf("StringBuffer: took %d ns per word%n", time / words.length);
    return s;
}
 
private static String testStringBuilder() {
    long start = System.nanoTime();
    StringBuilder sb = new StringBuilder();
    for (String word : words) {
        sb.append(word).append(',');
    }
    String s = sb.substring(0, sb.length() - 1);
    long time = System.nanoTime() - start;
    System.out.printf("StringBuilder: took %d ns per word%n", time / words.length);
    return s;
}

в конце печатает с -XX:+DoEscapeAnalysis с использованием Java 7 update 10

1
2
3
4
5
6
StringBuffer: took 69 ns per word
StringBuilder: took 32 ns per word
StringBuffer: took 88 ns per word
StringBuilder: took 26 ns per word
StringBuffer: took 62 ns per word
StringBuilder: took 25 ns per word

Тестирование с миллионом слов существенно не меняет результаты.

Вывод

  • Хотя стоимость использования синхронизации невелика, она поддается измерению, и если вы можете использовать StringBuilder, она предпочтительнее, так как она указана в Javadocs для этого класса.
  • Теоретически синхронизация может быть оптимизирована, но даже в простых случаях это еще не произошло.

Справка: можно ли оптимизировать синхронизацию? от нашего партнера JCG Питера Лоури из блога Vanilla Java .