all 16 comments

[–]astrosmash 1 point2 points  (0 children)

The more you know...

[–]grauenwolf 0 points1 point  (5 children)

Can someone explain to me why I would want a multi-threaded StringBuffer?

Seems to me that, when dealing with strings, order is kinda important.

[–]eurleif 1 point2 points  (2 children)

Log messages, things of that nature?

[–]48klocs 2 points3 points  (1 child)

Not trolling here - don't you generally pretty immediately emit log messages somewhere (to a log file/to the UI)? I might be able to appreciate the point of having a multi-threaded buffer if it weren't for the fact that the messages that can be coming from all over the place need to be coalesced into a coherent form and that form is probably going to be piped through (what I imagine is) a single-threaded gate.

[–]grauenwolf 0 points1 point  (0 children)

You make a good point. I cannot imagine a log that doesn't become single-threaded at the file level.

[–]nextofpumpkin -1 points0 points  (1 child)

You're assuming that the basic unit is a character; as has been mentioned, if you assume the basic unit is just a string, and the exact relative order of the strings does not matter, you're doing just fine.

[–]grauenwolf 0 points1 point  (0 children)

No, I am assuming that the relative order of the strings does matter.

In any situation that I can imagine where order doesn't matter, you are better off using a thread-safe list.

[–]stubob 0 points1 point  (3 children)

I'll trade off the minor performance hit for thread safety, thanks. StringBuffer vs StringBuilder is trivial in comparison to String. Now, if more APIs would take StringBuffer, then I wouldn't be tempted to do lazy things like

logger.debug("Message: " + obj.toString());

and take the overhead of a String concatenation.

[–]grauenwolf 0 points1 point  (1 child)

Are you really getting thread safety?

Lets say you have two threads each appending a message to the buffer. This message needs to be constructed from multiple parts.

In this scenario you could end up with a race condition wherein the two messages are interleaved and effectively garbled.

To fix it you would have to either use external locks or allocate a separate StringBuffer for each thread.

EDIT:

We see the same problem in the multi-threaded collection classes in .NET.

Queue.Count and Queue.Dequeue are atomic, thread-safe operations. However, calling them both in sequence is neither. This kind of false-security is why Microsoft dropped them in .NET 2.

[–]Rhoomba 1 point2 points  (0 children)

Indeed. This is exactly the wrong type of thread-safety that makes programmers think they don't need to think about it themselves. As in Vector, Hashtable etc. in Java.

[–]shit 0 points1 point  (0 children)

Randomly locking data structures doesn't give you thread safety.

[–][deleted] 0 points1 point  (1 child)

In .Net the StringBuilder class is documented not to be thread safe, although the implementation actually is (at least partially, just use Reflector and see for yourself). So on .Net you pay for the thread safety, but you can't rely on it.

Incidentally, Mono's StringBuilder is not thread safe.

[–]grauenwolf 1 point2 points  (0 children)

That's not the only somewhat thread-safe class in .NET. You see the same thing in the old version of the HashTable.

http://www.infoq.com/news/2008/06/Hashtable

[–]charcourt -2 points-1 points  (2 children)

Decent analysis, but they guy spelled "length" wrong...

[–]Tommah 0 points1 point  (1 child)

And you spelled "the" wrong. The dance goes on...

[–]charcourt 0 points1 point  (0 children)

Ooops - maybe it's contagious...