synchronized is slower but not worth worrying about

Overview

Often developer jump through hoops to avoid synchronization. There are justifications like; the application does lots of writes or reads. Without a clear idea of what "lots" means, they have no idea whether the optimisations they are using will help or just add complexity (and possibly make it slower)

Vector is slower than ArrayList, but that's not a good reason to avoid it

I prefer to use lock free objects and collections in a single threaded context. This is more for clarity than performance. It makes it obvious this code was designed to be single threaded. The performance difference by comparison is often trivial.

public static void main(String... args) throws IOException {
    for (int i = 0; i < 5; i++) {
        perfTest(new ArrayList());
        perfTest(new Vector());
    }
}

private static void perfTest(List objects) {
    long start = System.nanoTime();
    final int runs = 100000000;
    for (int i = 0; i < runs; i += 20) {
        // add items.
        for (int j = 0; j < 20; j+=2)
            objects.add(i);
        // remove from the end.
        while (!objects.isEmpty())
            objects.remove(objects.size() - 1);
    }
    long time = System.nanoTime() - start;
    System.out.printf("%s each add/remove took an average of %.1f ns%n", objects.getClass().getSimpleName(),  (double) time/runs);
}
prints
ArrayList each add/remove took an average of 3.0 ns
Vector each add/remove took an average of 38.5 ns
ArrayList each add/remove took an average of 2.0 ns
Vector each add/remove took an average of 4.4 ns
ArrayList each add/remove took an average of 2.4 ns
Vector each add/remove took an average of 4.6 ns
ArrayList each add/remove took an average of 2.0 ns
Vector each add/remove took an average of 4.6 ns
ArrayList each add/remove took an average of 2.3 ns
Vector each add/remove took an average of 4.5 ns
Using Vector is several times slower, and if all you application does is access the Vector it would make sense to use an ArrayList (and be glad you only have a trivial program to write) For real-world applications, a number of operations are needed and the cost of any one of these is relatively small.

The difference in time is only 2 ns (possibly more on some systems). If you have a task which takes a micro-second (called one million times per second) that operation will take 0.5% slower. If you have an operation which is used only 100,000 times per second, you might find you can't even measure the difference.

In summary, don't worry about performance problems until you have measured the difference you believe it would make. Otherwise you can waste a lot of time "optimising" something which won't make any difference or worse, is slower but you don't know it. (Due to the added complexity in "optimising" the solution)

Comments

  1. Curious, what accounts for
    1) Vectors first iteration being so slow
    2) If you switch the order you call perfTest, on the two systems i tested, it reduces the initial time for Vector and increases each iteration's time for ArrayList.
    What optimizations might be kicking in?

    ReplyDelete
  2. I'm curious about the same that @nicerobot.

    Besides, I agree with you, specially if your List comes from a database to be shown in a web page through internet.

    The spent time in obtaining the data from a remote machine to the server and to send it after processing to the client, could be hundred times more than the time used to allocated this data in the List.

    Furthermore, if your code is not thread safe and you change from single threaded to a multithread, the problems that could arise and the time to solve them will cost an arm and a leg.

    ReplyDelete
  3. Wouldn't there be some instruction reordering that would then impact the measured time of the first instruction in the loop in main ?

    That would explain the difference spotted by @nicerobot.

    I can't do it now, but testing with 2 ArrayLists / Vectors should then show the same difference

    ReplyDelete
  4. Am I right that all magic is in escape analysis - to eliminate locks if no contention was detected ?

    ReplyDelete
  5. @Vladimir Escape analysis is used to detect when a object is only used locally (and therefor in a single threaded manner) There is still a lot of code which uses StringBuffer for methods like toString(). Escape Analysis, in theory, can detect the object is never used in a multi-threaded context so not synchronization is required. In practice, StringBuffer is still slower than using StringBuilder.

    ReplyDelete
  6. @Peter
    The same picture is valid for Vector vs ArrayList (in terms of execution speed).
    I played a bit with tests and jvm options (like -XX:+DoEscapeAnalisys -XX:+EliminateLocks ), but i've got the same numbers as well with enabled options as well with disabled. Which is strange (for me).

    The explanation is required.

    ReplyDelete

Post a Comment

Popular posts from this blog

Low Latency Microservices, A Retrospective

Unusual Java: StackTrace Extends Throwable

System wide unique nanosecond timestamps