Java Forum / General / June 2007
synchronize vs gate
christopher@dailycrossword.com - 03 Jun 2007 20:43 GMT I have a singleton in a web service that provides a collection and self-updates it on a periodic basis:
doSelfUpdate()
create temporary collection (time consuming) syncronize update temporary collection from current collection (fast) create temporary reference 'old' to current collection point current collection reference to temporary collection end syncronize do stuff with 'old' collection (time consuming) done
getCollection() synchronize just waiting on monitor end synchronize return collection done
It seems to me each thread accessing the getCollection method must wait on the monitor every time it is accessed -- which is not what I want. I just want to open and close the gate for a few milliseconds while the self-update is being done. What do y'all think about something like this:
boolean isBusy=false;
doSelfUpdate() create temporary collection isBusy=true; update temporary collection from current collection create temporary reference 'old' to current collection point current collection reference to temporary collection isBusy=false; do stuff with 'old' collection done
getCollection() maxWait=10000 waited=0 while(isBusy && waited <maxWait) { waited+=500 if(waited>=MaxWait) log error; wait 500 } return collection done
IMHO this means each thread consuming getCollection is a tiny bit slower because it has a condition that must be tested, but as a group they are not waiting in line for the monitor. Is this right?
Lew - 04 Jun 2007 00:08 GMT > I have a singleton in a web service that provides a collection and > self-updates it on a periodic basis: [quoted text clipped - 9 lines] > do stuff with 'old' collection (time consuming) > done Try providing an SSCCE for your example. The use of pseudocode to resolve a Java question is not helpful.
> getCollection() > synchronize [quoted text clipped - 35 lines] > slower because it has a condition that must be tested, but as a group > they are not waiting in line for the monitor. Is this right? Assuming you mean the obvious transliteration to Java (e.g., that the producer and consumer methods run in separate threads), your second form will not work. getCollection() might return a version of collection containing none of the updates from invocations of doSelfUpdate() in other threads. In a heavily parallelized situation with multiple-core servers you very likely would end up with corrupted results.
(Incidentally, "collection" is an inadvisable name for a variable.)
Another thing is that your "wait" times are entirely arbitrary (also unspecified in your post). On what basis do you assess that any time you choose is greater or less than the time it would take to acquire a monitor?
Stick with the correct use of synchronization. You need to use concurrent idioms to handle concurrent issues.
 Signature Lew
christopher@dailycrossword.com - 04 Jun 2007 00:47 GMT > christop...@dailycrossword.com wrote: > > I have a singleton in a web service that provides a collection and [quoted text clipped - 72 lines] > -- > Lew thanx lew -- I don't care if the consumer gets an exact copy as long as each copy it is internally consistent. Sorry if I did not phrase my question well. I am not asking which runs faster or which takes less time. I am asking if I use synchronization doesn't each thread always have to wait for one and only one monitor? If I don't need everyone to have an exact copy -- only an internally consistent one -- can't I simply gate the process (with an arbitrary wait and retry)? In my mind (such as it is) all the consuming threads are waiting at the same time *only* while the singleton updates, rather than always waiting for each other.
Lew - 04 Jun 2007 01:07 GMT >>> What do y'all think about something like this: >>> boolean isBusy=false; [quoted text clipped - 17 lines] >>> return collection >>> done Lew wrote:
>> Stick with the correct use of synchronization. You need to use concurrent >> idioms to handle concurrent issues.
> thanx lew -- I don't care if the consumer gets an exact copy as long > as each copy it is internally consistent. Sorry if I did not phrase Do you care if a consumer /never/ gets the updates from a producer? That is the risk with the second idiom you provided.
> my question well. I am not asking which runs faster or which takes > less time. And I wasn't answering such a question. I was answering the question of whether your so-called "gate" approach would work at all.
> I am asking if I use synchronization doesn't each thread always have to wait for one and only one monitor? If I don't need > everyone to have an exact copy -- only an internally consistent one -- > can't I simply gate the process (with an arbitrary wait and retry)? No. If you do that the consumer might see none of the changes made by the producer(s), ever, or might get an inconsistent view.
> In my mind (such as it is) all the consuming threads are waiting at > the same time *only* while the singleton updates, rather than always > waiting for each other. Read the threading tutorials on Sun and elsewhere.
I don't know what problem you imagine you are avoiding by not synchronizing, but you aren't. A thread waits on a monitor only until another one releases it. It is the "waiting for one and only one monitor" that makes the code work; abandoning that is a recipe for disaster. Don't do it.
Your so-called "solution" to the non-existent "problem" will potentially cause threads to run much slower than with correct synchronization, orders of magnitude, several orders of magnitude, depending on your choice of "wait" [sic] times, and also to get very wrong results.
For a related "broken solution" see <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
Use synchronization. Do not use your "gate" approach. And start using Java for your examples. <http://mindprod.com/jgloss/sscce.html> <http://www.physci.org/codes/sscce.html>
Study threading and concurrency, and pay special attention to the Java "memory model".
Forget the gate. Use synchronization.
 Signature Lew
christopher@dailycrossword.com - 04 Jun 2007 07:03 GMT *snip*
> Forget the gate. Use synchronization. > > -- > Lew lew I have erased 4 replies to you already, so I will leave it at this -- I appreciate your time, I am not the dufus you seem to think I am, and I will continue to use pseodocode (as I have for 20 years) against your recommendation. I usually top-post, too.
No one would argue that *is not* a problem to use synchronized where it is unnecessary, and I believe in this case it is not. I am not certain (obviously) and would welcome a circumstance that proves me wrong, rather than a link to andrew's glossary gergoshsake, and some random page (double locking??) that is completely irrelevant.
Tom, I am using 1.4 until next week when my new server is online (1.5 doesn't run on this old beast), so 'volatile' has not been an option. I will look into it, as I think you have hit the nail on the head.
Lew - 04 Jun 2007 14:29 GMT > *snip* >> Forget the gate. Use synchronization. [quoted text clipped - 5 lines] > I have erased 4 replies to you already, so I will leave it at this -- > I appreciate your time, I am not the dufus you seem to think I am, and How do you conclude that I think that? I surely do not.
> I will continue to use pseodocode (as I have for 20 years) against > your recommendation. I usually top-post, too. The problem with pseudocode in a Java-specific question is that it obscures the very issues you are trying to resolve. I am not against pseudocode, only in favor of examples that actually exemplify.
Pseudocode cannot help resolve your question of whether to use synchronization, which volatile is part of, because your question of synchronization is particular to Java semantics.
As for top-posting, that's just deliberate rudeness. I can't believe you're actually bragging about it.
> No one would argue that *is not* a problem to use synchronized where > it is unnecessary, and I believe in this case it is not. I am not But synchronization /is/ necessary, that is my point. Why do you ignore it?
Your "gate" idiom simply would not work reliably in a multithreaded context. That was the point.
> certain (obviously) and would welcome a circumstance that proves me > wrong, rather than a link to andrew's glossary gergoshsake, and some > random page (double locking??) that is completely irrelevant. If you find it irrelevant, it's because you missed the point.
> Tom, I am using 1.4 until next week when my new server is online (1.5 > doesn't run on this old beast), so 'volatile' has not been an option. > I will look into it, as I think you have hit the nail on the head. The "volatile" keyword provides synchronization, but only fully in the new memory model. It is part of Java's synchronization mechanism, which I mentioned was required for your code to succeed. It does work in 1.4, but differently. I will forgo sending you the links that explain the differences, or the dangers.
 Signature Lew
Tom Hawtin - 04 Jun 2007 14:37 GMT > The "volatile" keyword provides synchronization, but only fully in the > new memory model. It is part of Java's synchronization mechanism, which > I mentioned was required for your code to succeed. It does work in 1.4, > but differently. I will forgo sending you the links that explain the > differences, or the dangers. As I understand it, 1.4 complies with the 1.5 spec in this regard.
Tom Hawtin
Lew - 04 Jun 2007 15:05 GMT Lew wrote:
>> The "volatile" keyword provides synchronization, but only fully in the >> new memory model.
> As I understand it, 1.4 complies with the 1.5 spec in this regard. They changed the memory model in Java 5, incorporating JSR 133. Among other changes, in 1.4 "volatile" only protected the given variable against synchronization issues. In J5+, all writes prior to a write to a volatile variable are readable by a thread that subsequently reads that volatile variable. This was the introduction of the "happens-before" concept. Now "volatile" is a much more powerful synchronization construct, much closer to "synchronized" itself.
 Signature Lew
Tom Hawtin - 04 Jun 2007 15:29 GMT >> As I understand it, 1.4 complies with the 1.5 spec in this regard. > [quoted text clipped - 5 lines] > "happens-before" concept. Now "volatile" is a much more powerful > synchronization construct, much closer to "synchronized" itself. As I say, as I understand it, the actual implementation of 1.4 complies with the 1.5 spec. Most of the tricky work of JSR 133 seems to have been coming up with a formalisation.
Tom Hawtin
Lew - 04 Jun 2007 15:37 GMT >>> As I understand it, 1.4 complies with the 1.5 spec in this regard. Lew wrote:
>> They changed the memory model in Java 5, incorporating JSR 133. Among >> other changes, in 1.4 "volatile" only protected the given variable [quoted text clipped - 3 lines] >> "happens-before" concept. Now "volatile" is a much more powerful >> synchronization construct, much closer to "synchronized" itself.
> As I say, as I understand it, the actual implementation of 1.4 complies > with the 1.5 spec. Most of the tricky work of JSR 133 seems to have been > coming up with a formalisation. That is very interesting information. I googled around quite a bit before answering, and all I found was JSR 133 results from 2004, well after 1.4 came out, and of course the JLS 3rd claims that the new memory model was only since J5. I had no idea any 1.4 implementation already embodied the behavior.
Every reference I've read about the memory model referred to 1.4 as implementing the "old" semantics and 5+ the "new", insofar as they mention it at all.
I presume you are referring specifically to Sun's implementation of 1.4. Do you know if it was only Sun, or all 1.4 implementations, or some other set that implemented the "new" semantics?
 Signature Lew
Robert Klemme - 04 Jun 2007 15:56 GMT >>>> As I understand it, 1.4 complies with the 1.5 spec in this regard. > [quoted text clipped - 25 lines] > 1.4. Do you know if it was only Sun, or all 1.4 implementations, or > some other set that implemented the "new" semantics? I believe most of the discussion was about the memory /model/ being flawed, not the /implementations/. So while implementations most of the time did what was reasonable the JLS did not enforce this behavior which in turn could lead to issues. Some of the discussion can be found here, I believe:
http://www.cs.umd.edu/~pugh/java/broken.pdf http://www.cs.umd.edu/~pugh/java/memoryModel/
http://www.ibm.com/developerworks/library/j-jtp02244.html http://www.ibm.com/developerworks/library/j-jtp03304/
http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg00404.html
Kind regards
robert
Lew - 04 Jun 2007 16:03 GMT Tom Hawtin wrote:
>>> As I say, as I understand it, the actual implementation of 1.4 >>> complies with the 1.5 spec. Most of the tricky work of JSR 133 seems >>> to have been coming up with a formalisation. Lew wrote:
>> I presume you are referring specifically to Sun's implementation of >> 1.4. Do you know if it was only Sun, or all 1.4 implementations, or >> some other set that implemented the "new" semantics?
> I believe most of the discussion was about the memory /model/ being > flawed, not the /implementations/. So while implementations most of the > time did what was reasonable the JLS did not enforce this behavior which > in turn could lead to issues. Which is why I'm curious which 1.4 JVM's implemented the "broken" behavior, and which implemented the behavior later formalized in JSR133.
In any event, I wouldn't recommend to the OP that they rely on behavior of the 1.4 JVM that is not enforced by the JLS for that version. Not only that, but Sun's 1.4 implementation is now officially in "End-of-Life", and the OP has stated that they are on the verge of moving to the next old Java version, so the point is moot for them.
 Signature Lew
Robert Klemme - 04 Jun 2007 16:20 GMT > Tom Hawtin wrote: >>>> As I say, as I understand it, the actual implementation of 1.4 [quoted text clipped - 13 lines] > Which is why I'm curious which 1.4 JVM's implemented the "broken" > behavior, and which implemented the behavior later formalized in JSR133. I /believe/ Sun's JDK's were ok but I cannot give you references to material confirming this. I'm sorry.
> In any event, I wouldn't recommend to the OP that they rely on behavior > of the 1.4 JVM that is not enforced by the JLS for that version. Not > only that, but Sun's 1.4 implementation is now officially in > "End-of-Life", and the OP has stated that they are on the verge of > moving to the next old Java version, so the point is moot for them. Yeah, definitively agree!
Kind regards
robert
Tom Hawtin - 04 Jun 2007 01:07 GMT > I have a singleton in a web service that provides a collection and > self-updates it on a periodic basis: [quoted text clipped - 16 lines] > return collection > done The obvious thing to do (from Java 1.5 spec, and 1.4 implementation) is to make the reference to the collection volatile. Keep the lock in doSelfUpdate, but not getCollection. Alternatively just use java.util.concurrent.ConcurrentHashmap.
Tom Hawtin
Robert Klemme - 04 Jun 2007 15:30 GMT >> I have a singleton in a web service that provides a collection and >> self-updates it on a periodic basis: [quoted text clipped - 21 lines] > doSelfUpdate, but not getCollection. Alternatively just use > java.util.concurrent.ConcurrentHashmap. Yet another alternative would be to use a ReadWriteLock that is held during update of the reference only and use an immutable collection. This of course works best if it is made sure through other means that there is just one updater at a time - although two concurrent updaters might only cost additional CPU. The logic should still work, you only get two (or n) updates of the reference in a short period of time. If the update process itself needs additional synchronization that can be either provided by another Lock or different logic. Difficult to speculate without knowing more detail...
Kind regards
robert
Karl Uppiano - 06 Jun 2007 04:38 GMT In my 10 years of writing in Java, I only found the need to roll my own synchronization one time: We needed a Mutex or CriticalSection, and prior to 1.5, Java had no such thing. We finally got it working, but it was a nightmare.
People tend to think the original Java synchronization was lame, but it is surprising how well it works, and how rarely you need anything else.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|