6 ms·
How about just using StringBuilder unless you really (that 0.01% case) need thread synchronization of StringBuffer? I'm a C++ programmer mainly, surely all Jav
by vardump 10y ago
How about just using StringBuilder unless you really (that 0.01% case) need thread synchronization of StringBuffer?
I'm a C++ programmer mainly, surely all Java programmers know why StringBuffer is bad by now?
Article also has a pretty pointless microbenchmark.
Most synthetic microbenchmarks are questionable by default. Even worse when there's any kind of limited resource utilization such as thread synchronization involved.
Synthetic microbenchmarks assume all the resources are just for them. Whole CPU instruction and data cache, all synchronization bandwidth, all memory bandwidth, etc.
Use profiling instead of microbenchmarks.
- lmm 10y ago> How about just using StringBuilder unless you really (that 0.01% case) need thread synchronization of StringBuffer? You wouldn't necessarily know, or notice - your users would just experience occasional random crashes. How about just using StringBuffer unless you really (that 0.01% case) need the performance of StringBuilder? As you say, profiling is the right way to approach these things.
- vardump 10y agoAre you playing a devil's advocate? I just don't think this is the right place to do the synchronization. Wouldn't a Double box (that's really a "SynchronizedDouble") be silly? Besides, can you think of any legitimate reason to concurrently append to a StringBuffer in the first place?
- kodablah 10y ago> How about just using StringBuffer unless you really (that 0.01% case) need the performance of StringBuilder? Because when writing new code you should opt-in to thread safety, not out. Collections are not concurrent by default, there is no `unsynchronized` or `non-volatile` keywords, etc. StringBuilder:StringBuffer::HashMap:ConcurrentHashMap. Also, if the performance benefit requires negligible upfront cost (e.g. providing length to ArrayList if known) you should do it and build it in your muscle memory as the default approach. The problem is StringBuffer (unlike many other parts of the stdlib) was the only approach available for a long time so people need to change their default way of thinking. Luckily it's been a long time since 1.5 and basically everyone has changed.
- Someone 10y agoI don't think thread-safety is a big concern for string building APIs. I expect 90% or more of all uses of StringBuffer are easily verified to be used from only one thread because they allocate an instance, assign it to a local variable, append to it a few times, and finally get the string that was built exactly once. Actually, I don't see why it would take a very smart compiler to do this kind of escape analysis and automatically and safely replace StringBuffer by StringBuilder where possible. The only large downside I can see of that is that it would require the compiler to know quite a bit of the semantics of the standard library. If you refactor your code and pass the StringBuffer to (small) helper functions, doing this would be more work, but it would not get essentially harder.
- hyperpape 10y agoYou're right about thread safety. And when you do want it, you probably want more guarantees than StringBuffer gives you (ability to synchronize multiple inserts, for instance). With regard to the sufficiently smart compiler: it seems like you'd need every method the StringBuffer is passed to be final to do that kind of analysis. In the case where you're writing: public void foo(List<String> strings) { StringBuffer x = new StringBuffer(); for (String s: strings) { x.append(s); } } You could conceivably do the analysis at compile time. But the whole idea behind the JIT is that you don't need to. If the code is hot, it'll get compiled, and you'll probably be fine thanks to removing all the synchronization, while if it's not hot no one cares.
- Someone 10y agoYou're right, I forgot that all methods are implicitly virtual by default in Java.
- vardump 10y agoNot quite same as "virtual" in C++ though. Java methods can still be inlined at runtime. I wish C++ had a runtime that could do same, inline smaller virtual methods, function pointers and shared library (.dll/.dylib/.so) calls at runtime. It could also do other transformations, like optimize those branches away it can prove to be always true or false. It could flatten most abstractions, removing redundant parameter checks and call frame setups/teardowns. It could also do CPU (instruction set) specific optimizations. I think C++ runtime that does this partial JITting is possible, but not easy. However, the benefits are interesting. While getting there won't be easy, you can achieve faster than native performance. Something like this has already been actually done. Some examples below. QuaC: http://digitalassets.lib.berkeley.edu/techreports/ucb/text/CSD-94-792.pdf http://digitalassets.lib.berkeley.edu/techreports/ucb/text/C... DynamoRio: DynamoRio had some early success JITting native binaries resulting faster than native performance. Unfortunately current versions are slower than native. https://github.com/DynamoRIO/dynamorio https://github.com/DynamoRIO/dynamorio). https://dspace.mit.edu/bitstream/handle/1721.1/87441/54863587-MIT.pdf?sequence=2 https://dspace.mit.edu/bitstream/handle/1721.1/87441/5486358...
- stickfigure 10y agoThe only sane way to write multithreaded code is to assume all libraries are not thread-safe unless explicitly declared as such, and to carefully manage critical sections. There's no point in "defaulting" to threadsafe libraries; just because you use StringBuffer does not mean your code is threadsafe. If you don't understand your critical sections, you're almost certainly screwing up.
- Tharkun 10y agoThat's nonsense. I can't think of any realistic examples in which it would be useful for multiple threads to write to the same StringBuffer. You might as well sprinke random and pointless synchronized blocks around your code. The magical synchronization fairy will give you a false sense of correctness.
- shiv86 10y ago99% of the time you initialize StringBuilder during a method call. Each method call stores it’s variables on the stack and each thread has its own stack. So in the above 99% usecases StringBuilder is thread safe by default. Use cases for StringBuffer are very limited …I can’t even think of an example where I would use it.
- DannyB2 10y agoIn most cases you WOULD know that StringBuilder is just fine and no thread contention exists. Most common uses of StringBuilder are where the StringBuilder is a local variable used within a single function to build up a string, and then to give you the actual string that was built up. After that the StringBuilder goes out of scope and the garbage collector will eat it up when it gets hungry. The string that StringBuilder gave you is immutable, therefore no other thread can change its value. (And hence the reason why StringBuilder is useful -- it is like a mutable string.)
- hyperpape 10y agoProfiling has a lot of its own pitfalls. Use a sampling profiler and your calls to StringBuilder might get compiled so that there are no safepoints inside them and you never see them[0]. Use instrumentation, and you can massively over weight short methods because of the overhead. [0] I would think this can realistically happen for StringBuilder calls, but I'm not 100% sure.
- vardump 10y agoI just read this: http://psy-lob-saw.blogspot.com/2015/12/safepoints.html http://psy-lob-saw.blogspot.com/2015/12/safepoints.html Wow, I had no idea how bad sampling profilers are on JVM. And apparently JVM profiling in general. So collecting a stack trace sample requires a thread being suspended at a safepoint. And a global safepoint requires suspending all threads? Sampler that needs to do that will surely not only miss real CPU time consumer but also significantly alter performance behavior. Instrumentation is indeed often a pretty bad option as well. Is it possible to resolve JVM stack traces captured from kernel side (Windows and Linux have mechanisms for this)? That would certainly get around any safepoint restrictions, right?
- hyperpape 10y agoYeah, I think there are ways to get around it, though I'm not super familiar with all of the details. I think that Java Mission Control from Oracle might not have the safepoint bias, and in open source there are also some attempts: https://github.com/RichardWarburton/honest-profiler/wiki https://github.com/RichardWarburton/honest-profiler/wiki.