public
Last active

A benchmark to compare String.intern() to ConcurrentHashMap.putIfAbsent()

  • Download Gist
InternBench.java
Java
1 2 3 4 5 6 7 8 9 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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
import java.util.*;
import java.util.concurrent.*;
 
/**
* java version "1.7.0_03"
* OpenJDK Runtime Environment (IcedTea7 2.1.1pre) (7~u3-2.1.1~pre1-1ubuntu2)
* OpenJDK 64-Bit Server VM (build 22.0-b10, mixed mode)
*
* javac InternBench.java
* java -Xmx1g -Xms1g -XX:+PrintGCDetails -XX:NewRatio=1 -XX:+PrintCompilation -verbose:gc -classpath . InternBench
*
* Results:
*
* intern() many different strings:
* ================================
* count initial intern lookup same string lookup equal string
* 1'000'000 40206 34698 35000
* 400'000 5198 4481 4477
* 200'000 955 828 803
* 100'000 234 215 220
* 80'000 110 94 99
* 40'000 52 30 32
* 20'000 20 10 13
* 10'000 7 5 7
*
* Manual "interning" with ConcurrentHashMap:
* ==========================================
* 1'000'000 411 246 309
* 800'000 352 194 229
* 400'000 162 95 114
* 200'000 78 50 55
* 100'000 41 28 28
* 80'000 31 23 22
* 40'000 20 14 16
* 20'000 12 6 7
* 10'000 9 5 3
*
*/
public class InternBench {
 
private static long timerStart = 0;
private static long timerEnd = 0;
 
public static void main(String[] args){
startTimer();
Set<String> candidates = new HashSet<String>();
Random rand = new Random();
for(int i = 0; i < 1_000_000; i ++){
String candidate = Long.toString(rand.nextLong(),36);
candidates.add(candidate);
}
endTimer("Generated candidate strings in %d ms");
putAll(candidates);
}
 
private static void internAll(Set<String> candidates){
startTimer();
for(String s : candidates){
s.intern();
}
endTimer("Initial interning done in %d ms");
startTimer();
for(String s : candidates){
s.intern();
}
endTimer("Identity lookup done in %d ms");
System.out.println("meuh");
Set<String> copies = new HashSet<String>();
for(String s : candidates){
copies.add(new String(s));
}
System.out.println("foo");
startTimer();
for(String s : copies){
s.intern();
}
endTimer("Equals lookup done in %d ms");
}
private static void putAll(Set<String> candidates){
ConcurrentHashMap<String,String> pool = new ConcurrentHashMap<String,String>();
// warmup the methods of ConcurrentHashMap and the other java.util.concurrent stuff
startTimer();
for(int i = 0; i < 10000; i ++){
String s = Integer.toString(i);
pool.putIfAbsent(s,s);
pool.putIfAbsent(s,s);
}
for(int i = 0; i < 10000; i ++){
String s = Integer.toString(i);
pool.putIfAbsent(s,s);
}
endTimer("JIT warmup done in %d ms");
pool = new ConcurrentHashMap<String,String>();
startTimer();
for(String s : candidates){
pool.putIfAbsent(s,s);
}
endTimer("Initial put done in %d ms");
startTimer();
for(String s : candidates){
pool.putIfAbsent(s,s);
}
endTimer("Identity lookup done in %d ms");
System.out.println("meuh");
Set<String> copies = new HashSet<String>();
for(String s : candidates){
copies.add(new String(s));
}
System.out.println("foo");
startTimer();
for(String s : copies){
pool.putIfAbsent(s,s);
}
endTimer("Equals lookup done in %d ms");
}
private static void startTimer(){
timerStart = System.nanoTime();
}
private static void endTimer(String messagePattern){
timerEnd = System.nanoTime();
long msElapsed = (timerEnd - timerStart)/1000000;
System.out.println(String.format(messagePattern, msElapsed));
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.