• Post Reply Bookmark Topic Watch Topic
  • New Topic

StringBufferPool (why not Threadsafe) ?

 
Stefan Geelen
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,
I made a StringBufferPool class with the idea to share the use of StringBuffers instead of recreating them each time. Here is the code

If another instance of a class needs a StringBuffer it calls the pool (in a method) with following pattern:

This works if there is only one thread running. With multiple threads, I'm getting strange results.
The seems odd to me as the buf.toString() should have made a copy (using .toString()) before the StringBuffer is returned to the Pool.
Any suggestions ?
 
karl koch
Ranch Hand
Posts: 388
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi
i did not study your code in detail i just have some general advice:
1. your pool should be an object which requires an instance -> no static methods and variables. this is more object oriented.
2. take a look at ArrayList and perhaps you can consider it as a replacement for the Vector. ArrayList is not synchronized (and since you take care of synchronization yourself you it doesnt need to be synced) and should be faster (there is a thread on javaranch - which i could not find - that explains that depending on the version of JDK Vector is still faster than ArrayList even though it shouldnt be that way)
3. if you stick with Vector you should remove() the StringBuffer from instead of using lastElement() and then decrement the size. makes more sense to me.
4. perhaps (may be some other ranchers can give some hints) you should not use a try/finally when using a StringBuffer from your pool.

again, this makes more sense to me.
5. may be you can give some details about the " strange behaviour"
k
 
Stefan Geelen
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dear,
thanks for your response.
I'll try the various remarks you give in the next days and keep you posted.
Now with the strange behavior I mean that if the stringbuffer is returned to the pool and another method gets the stringbuffer from the pool the stringbuffer still contains the previous content.
So I first thaught the the reference to the StringBuffer is kept somewhere in the first method but this is not true. So I have no clue why this happens.
Regards,
Stefan
 
Mr. C Lamont Gilbert
Ranch Hand
Posts: 1170
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The class looks thread safe to me. I do not see what you are doing to ensure that the same StringBuffer is not returned to seperate requests.
 
Stefan Geelen
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dear,
the idea of the Pool is just that the same stringbuffer, once returned to the pool, can be reused by *another* Thread.
So I do nothing special to prevent that a StringBuffer is not returned to the same request (I suppose you mean by request 'thread')?
Regards,
Stefan
 
Peter den Haan
author
Ranch Hand
Posts: 3252
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I would submit that the entire idea is quite possibly misguided and even counterproductive. My advice would be to forget about the StringBuffer pool until a profiler has proven that StringBuffer creation is a bottleneck. And then decide on a course of action after a thorough study of the options.
Usually, after you're through with your StringBuffer manipulation, you retrieve the result as a String. You should know that that String is backed by the same char[] array as the StringBuffer. The next time you modify the buffer, the char[] array is cloned (after all, the String must remain unmodified). So you see that StringBuffer pooling is not nearly as smart as you perhaps thought it was; you save yourself the creation of the little StringBuffer object but at the cost of cloning a possibly large char[] array behind the scenes -- and it is not at all obvious which is more costly.
It gets worse. The char[] array does not get resized, so if the previous use of the StringBuffer generated a very large string you end up with a ridiculously oversized char[] array. Remember, this array ends up backing your String no matter how small the contents of the String are! As a consequence, memory consumption might well skyrocket and performance decrease.
Bottom line: remember the first rule of optimization.
- Peter
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I agree strongly with PdH here. (Which is a good policy in general, really.) It's very unlikely that you'd get any significant benefit from pooling StringBuffers - and quite possibly it will be detrimental. Certainly it's somewhat complex to create a pool, and can lead to annoying bugs which nullify any benefit you may get (as you've seen). The only reason I can imagine to do this is as a learning excercise - how to make an object pool, how to make code thread-safe, how to debug it, etc. All potentially useful to learn about, even if there's no immediate use for the code.
With that in mind, I'll also agree with CLG (which again is a good idea in general) and say that I don't see any inherent problem with the code you've written so far - but it's important that the pool be used correctly by client code to ensure thread safety. The two possible prolems I see are (a) make sure a single StringBuffer is never put() more than once into the pool, unless it's been retrieved by a get() in between, and (b) make sure you don't use a given StringBuffer reference at all after returning it to the pool. There are ways to enforce both of these in your pool, but they'll make the code even more complex and/or slower. If you really want to continue with this just for learning purposes, let us know; otherwise I'll stop now.
 
Stefan Geelen
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dear,
many thanks for the responses to you all. I'll accept the answer that this pool is not a good idea (no performance gain).
But uptill now nobody has explained what is wrong with the code I have written.
I still do not understand what goes wrong where.
So If some-one can shed a light on this (just for educational reason) please do so.
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, CLG and I don't see anything particularly wrong in the code you've shown, but (a) there could be something more subtle that just doesn't jump out at us, or (b) there could be something wrong in the way the code is called. As an example of the latter:

Here the StringBuffer is used again after it's been returned to the pool. The problem is that once it's returned to the pool, another thread might get() it and start using it, leading to concurrent access.
Another example:

Here, there are two put() statements. This results in two different entries in the pool, both pointing to the same StringBuffer. This means that the next two threads which call get() will get a reference to the same StringBuffer - which means that two different threads can be concurrently accessing the same buffer. Which again, is what you need to avoid.
[ March 27, 2003: Message edited by: Jim Yingst ]
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!