Prev: Const correctness (was Re: Oppinion on 'least priviledge', 'const correctness', etc.)
Next: Simple Hack To Get $2500 To Your PayPal Account.
From: Peter Duniho on 21 Jul 2010 03:30 markspace wrote: > Peter Duniho wrote: > >> It is worth noting that the reference to the object itself need not be >> the thing that is subject to synchronization. Anything that >> introduces the necessary memory barrier is sufficient. > > One caveat here: "anything" must be the same thing in all threads which > access the shared data in question. If thread A locks objectA, and > thread B locks objectB, they are in no way synchronized, nor is there > any happens-before relationship establish for any shared data they access. Right. >> So, for example, any of the "storing a reference to it" examples above >> are actually satisfied by any data being stored in the described >> location, so long as the data being published has been initialized >> prior to storage _and_ when the data is later read by a different >> thread, that thread first retrieves whatever data was in fact stored >> in the described location. > > I don't think this is correct for all of the examples Joshua listed. For > example, storing a reference to a field that is properly guarded by a > lock does NOT create a happens-before relationship for "any data" later > read by a different thread. Yes, it does. As long as the different thread reads the synchronized data first (which is what I wrote). > Actually, the more I reread your statement, the more I'm sure I have no > idea what the heck you are actually trying to say. I can't think of any > combination of events where the events you listed actually bear on each > other. Could you produce an example where that's relevant? class Test { private volatile boolean set = false; private int data = 0; void methodA() { data = 5; set = true; } void methodB() { if (set) { System.out.print(data); } } } In the above example, if methodA() is executed on one thread, and then methodB() is executed in a different thread, methodB() is guaranteed to see the new value for "data". Note that I didn't need to store the reference to the Test object anywhere in order to ensure synchronization. I didn't need to store a reference to _anything_, for that matter. It suffices to introduce the partial memory barrier provided by the volatile write and read. All writes that occur before the volatile write to a variable are guaranteed to be visible in any other thread after it performs the volatile read from the same variable. Pete
From: Peter Duniho on 21 Jul 2010 03:31 markspace wrote: > Joshua Cranmer wrote: > >> Immutability is the easiest way to guarantee safe publication: final >> fields guarantee that they can be used by any thread safely. > > Note quite. Final fields by themselves don't guarantee immutability or > safe publication. An immutable object must: > > * All fields are final. > * It is properly constructed. (No "this escapes." That bit is important.) > * Its state cannot be modified after construction. > > Those three things must hold for an object to be treated as immutable by > the JVM. Mess up any one, and poof, no more immutability. I would be interested in seeing an example where your third point is violated but the first point is not.
From: markspace on 21 Jul 2010 04:14 Peter Duniho wrote: > class Test > { > private volatile boolean set = false; > In the above example, if methodA() is executed on one thread, and then > methodB() is executed in a different thread, methodB() is guaranteed to > see the new value for "data". Yes, for volatile, this works. Volatile fields have special semantics which prevent re-ordering reads and writes by the compiler, so this is guaranteed to work. I said it didn't work for all of the cases Joshua listed, particularily the synchronized one. Replace the volatile with a synchronized block and it won't work anymore. Just trying to let other folks know what works and what doesn't. I think you knew this already, just that you didn't touch all the bases when you mentioned it originally. class Test { private boolean set; private int data; void methodA() { data = 5; synchronized( this ) { set = true; } } void methodB() { synchronized( this ) { if (set) { System.out.print(data); // may print "0" } } } }
From: markspace on 21 Jul 2010 04:22 Peter Duniho wrote: > markspace wrote: >> Joshua Cranmer wrote: >> >>> Immutability is the easiest way to guarantee safe publication: final >>> fields guarantee that they can be used by any thread safely. >> >> Note quite. Final fields by themselves don't guarantee immutability >> or safe publication. An immutable object must: >> >> * All fields are final. >> * It is properly constructed. (No "this escapes." That bit is >> important.) >> * Its state cannot be modified after construction. >> >> Those three things must hold for an object to be treated as immutable >> by the JVM. Mess up any one, and poof, no more immutability. > > I would be interested in seeing an example where your third point is > violated but the first point is not. class Mutable { private final List<String> names; public Mutable() { names = new List<String>(); names.add("Joe"); names.add("Jim"); } public List<String> getNames() { return names; } } This class would be immutable except for the fact that the private final variable "names" escapes and could be modified. If the getNames() method is removed, then the class is immutable and can be published even in a data race. And I know what's coming next, but it really is immutable if the getter is removed. The JLS was designed to work this way because String has to be immutable, and String initializes itself the same way, so the JLS was constructed to make this kind of initialization safe and immutable.
From: Lew on 21 Jul 2010 09:46
Peter Duniho wrote: >> class Test >> { >> private volatile boolean set = false; >> >> In the above example, if methodA() is executed on one thread, and then >> methodB() is executed in a different thread, methodB() is guaranteed >> to see the new value for "data". markspace wrote: > Yes, for volatile, this works. Volatile fields have special semantics > which prevent re-ordering reads and writes by the compiler, so this is > guaranteed to work. > > I said it didn't work for all of the cases Joshua listed, particularily > the synchronized one. Replace the volatile with a synchronized block and > it won't work anymore. It will so, as long as they synchronize on the same lock or monitor. > Just trying to let other folks know what works and what doesn't. I think > you knew this already, just that you didn't touch all the bases when you > mentioned it originally. > > class Test > { > private boolean set; > private int data; > > void methodA() > { > data = 5; > synchronized( this ) { > set = true; > } > } > > void methodB() > { > synchronized( this ) { > if (set) > { > System.out.print(data); // may print "0" > } > } > } > } You're mistaken. The assignment in 'methodA()' of 'data' /happens-before/ the write to 'set', which latter is synchronized. The read in 'methodB()' of 'data' /happens-after/ the read of 'set', which latter is synchronized on the same monitor. Therefore the read is guaranteed to see the write. -- Lew |