public static void main(String[] args) {
        ThreadLocalDirectoryBenchmark benchmark = new ThreadLocalDirectoryBenchmark();
        long end;
        System.out.println("ThreadLocalDirectory<Integer, Integer>");
        long start = System.currentTimeMillis();
        benchmark.sumFromMultipleThreads();
        end = System.currentTimeMillis();
        System.out.println("Elapsed using threadlocals: " + (end - start) + " ms.");
        System.out.println("AtomicInteger");
        start = System.currentTimeMillis();
        benchmark.sumAtomicFromMultipleThreads();
        end = System.currentTimeMillis();
        System.out.println("Elapsed using atomic integer: " + (end - start) + " ms.");
        System.out.println("volatile int += volatile int");
        start = System.currentTimeMillis();
        benchmark.overwriteVolatileFromMultipleThreads();
        end = System.currentTimeMillis();
        System.out.println("Elapsed using single shared volatile: " + (end - start) + " ms.");
        System.out.println("int += int");
        start = System.currentTimeMillis();
        benchmark.overwriteIntegerFromMultipleThreads();
        end = System.currentTimeMillis();
        System.out.println("Checksum: " + benchmark.naiveCounter);
        System.out.println("Elapsed using shared int: " + (end - start) + " ms.");
        System.out.println("ThreadLocalDirectory<IntWrapper, IntWrapper>");
        start = System.currentTimeMillis();
        benchmark.sumMutableFromMultipleThreads();
        end = System.currentTimeMillis();
        System.out.println("Elapsed using threadlocal with mutable int wrapper: " + (end - start) + " ms.");
    }
This just bangs on a shared to give some sort of lower bound for time
elapsed.
vespajlib/developernotes/ThreadLocalDirectoryBenchmark.java