synchronize vs gate

C

christopher

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?
 
L

Lew

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

Try providing an SSCCE for your example. The use of pseudocode to resolve a
Java question is not helpful.
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?

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.
 
C

christopher

Try providing an SSCCE for your example. The use of pseudocode to resolve a
Java question is not helpful.









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.

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.
 
L

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

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.
 
T

Tom Hawtin

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

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
 
C

christopher

*snip*
Forget the gate. Use synchronization.

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.
 
L

Lew

*snip*

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

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.
 
T

Tom Hawtin

Lew said:
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
 
L

Lew

Tom said:
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.
 
T

Tom Hawtin

Lew said:
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.

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
 
R

Robert Klemme

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.

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
 
L

Lew

Tom said:
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?
 
R

Robert Klemme

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?

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
 
L

Lew

Robert said:
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.
 
R

Robert Klemme

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
 
K

Karl Uppiano

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,016
Latest member
TatianaCha

Latest Threads

Top