• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Paul Clapham
  • Ron McLeod
  • Jeanne Boyarsky
  • Tim Cooke
Sheriffs:
  • Liutauras Vilda
  • paul wheaton
  • Henry Wong
Saloon Keepers:
  • Tim Moores
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Frits Walraven
Bartenders:
  • Piet Souris
  • Himai Minh

StringBuilder slower than StringBuffer!?

 
Ranch Hand
Posts: 154
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
StringBuilder javadoc API: "Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations."

Both StringBuilder and StringBuffer classes extend AbstractStringBuilder class. The methods of StringBuffer are synchronized. Naturally the above statement would make sense and expected.

But the below test executed multiple times always gives faster execution times for StringBuffer! using JDK 1.6.0_10.



Any explanation? Am i missing something obvious in the above code?
 
Rancher
Posts: 13459
Android Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
there is always an overhead associated with synchronising code, even if things are much better in Java 6. In most cases the class is used in a single thread so the synchronisation makes it slower while offering no benefit.
 
Vin Kris
Ranch Hand
Posts: 154
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
David, I would expect StringBuffer to be slower since its methods are synchronized. But here StringBuilder is slower.
 
Bartender
Posts: 9626
16
Mac OS X Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I am always suspicious of micro-benchmarks like this. If I run your code as-is, I get the following result:


However, if I put the code that evaluates StringBuffer first, I get this result:



Because of the way the VM optimizes code as it runs, it's easy to get unexpected results.
In any case, in any non-trivial program, the performance difference between these two classes will probably be negligible.
 
David O'Meara
Rancher
Posts: 13459
Android Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
well firstly 1000 iterations isn't much. I'd bump it up a few orders of magnitude. Try averaging 10,000 times over 10,000 concatenations. You should also look at other methods since you aren't really exercising the API
 
Vin Kris
Ranch Hand
Posts: 154
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm glad you got the result where StringBuffer is slower.

But I did try the other way also i.e., the code you tested. Even then it was slower. That's why I posted it here hoping to get an explanation.
 
author
Posts: 23919
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Any explanation? Am i missing something obvious in the above code?



Interesting.... give me a sec.

Wow, you are right. StringBuffer is faster.... hmmmm.... give me another sec.


Okay, it looks like you are being interferred with (Probably by the JIT). Place your test code within a loop, and run it many times. You will noticed that StringBuffer is only faster for only the first iteration.

Once the program warms up, which is within a second, StringBuilder is faster.

Henry
 
Joe Ess
Bartender
Posts: 9626
16
Mac OS X Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Vin Kris:

But I did try the other way also i.e., the code you tested. Even then it was slower. That's why I posted it here hoping to get an explanation.



There's two changes I made to your code: one was label the output. The second was to print the output immediately after the test was executed, so we can see in the output which test is executed first.
My wild guess: you changed the code but didn't recompile. Try making those two changes and see if you get the same results.
Java Platform Performance is a good resource when you are starting to think about how Java works.
[ September 25, 2008: Message edited by: Joe Ess ]
 
Vin Kris
Ranch Hand
Posts: 154
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You are right Henry. Thanks.

I had tried a lot of different ways including what you suggested. Then i increased the individual append loop count with more APIs included (david's suggestion) and loop count overall. StringBuilder is marginally faster than StringBuffer. Considering it's in Nanos, no big deal. But it does make me wonder what the heck is happening inside. I'd rather use StringBuffer itself if this test shows same result in different versions of JVM and by different vendors.
 
Henry Wong
author
Posts: 23919
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here is a little background, that may be relevant:

Java 5 improved synchronization, of uncontended lock grabs, immensely. So, if StringBuffer is not shared between threads, a lock grab can occur in less than 100 nanos -- basically really really fast.

Java 6/7 (not sure which) improved it even more. With the "escape analysis" optimization, any objects instantiated locally, and doesn't escape the method, is deemed to be unable to be shared between threads. Hence, synchronization requests are completely removed.

Henry
 
David O'Meara
Rancher
Posts: 13459
Android Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Just to quantify my results based on Henry's comment on the various Java versions:

All results taken from max, min and average of 10,000 runs.
All numbers in ns

Compiled by Java 6 running in Java 6
StringBuilder min: 91353 max: 30748496 av: 122261
StringBuffer min: 1041405 max: 17018873 av: 1316670

Compiled by Java 5 running in Java 6
StringBuilder min: 82623 max: 20051455 av: 121638
StringBuffer min: 1044756 max: 6598961 av: 1315066

Compiled by Java 5 running in Java 5
StringBuilder min: 91000 max: 24705000 av: 129188
StringBuffer min: 1561000 max: 7593000 av: 1777096

Java 1.4 (converted from milliseconds)
StringBuffer min: 3000000 max: 18000000 av: 5000000

Now I was just using b.append(i).append(String.valueOf(i)), but to me the StringBuilder shows comparable performance when run on the Java 5 and Java 6 versions, and the Buffer shows a noticeable improvement both from Java 4 to Java 5 and Java 5 to Java 6. In my tests the Builder was always an order of magnitude faster on average.

The other test not done would be to test the StringBuffer between multiple threads and see how it performs with the Java 5 and Java 6 single thread results.
 
Ranch Hand
Posts: 1923
Scala Postgres Database Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Not much difference here:

StringBuildBuff.sh:


true means: StringBuilder
false: StringBuffer.


Those scripts are mostly generated automatically, hence not too elegant.
They allow to increase the number of iterations, usage of different jdks: 1.5, 1.6 - mode client or server.

The structure of the program is identical and they are started separately.
Timing is done from outside, because linux allows to measure the time used by that thread - a meanwhile running virus scanner isn't disturbing the results - okay - we need no virusscanner.
A meanwhile running cronjob. Searchindex regeneration.
[ September 27, 2008: Message edited by: Stefan Wagner ]
 
That's my roommate. He's kinda weird, but he always pays his half of the rent. And he gave me this tiny ad:
Free, earth friendly heat - from the CodeRanch trailboss
https://www.kickstarter.com/projects/paulwheaton/free-heat
reply
    Bookmark Topic Watch Topic
  • New Topic