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 20 Jul 2010 23:57 Joshua Cranmer wrote: > On 07/20/2010 10:06 PM, Alan Gutierrez wrote: >> It was all the talk about the importance of immutability that made me >> worry that field assignments that were unsynchronized or non-volatile >> could be hidden from the receiving thread. This bit of documentation >> that I missed, plus a first reading of JLS Ch 17, put that to rest. > > Immutability is the easiest way to guarantee safe publication: final > fields guarantee that they can be used by any thread safely. Any other > type of object has to be safely published. Java Concurrency in Practice > lists four ways of doing it: > * Initializing an object reference from a static initializer > * Storing a reference to it into a volatile field or AtomicReference > * Storing a reference to it into a final field of a properly constructed > object > * Storing a reference to it into a field that is properly guarded by a > lock. 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. 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. Pete
From: Peter Duniho on 21 Jul 2010 00:12 Alan Gutierrez wrote: > [...] >> I recall seeing something like this earlier today. >> >> public void foo(int number) { >> final List<Integer> list = new ArrayList<Integer>(); >> list.add(number); >> new Thread(new Runnable() { >> final List<Integer> happensAfter = list; >> public void run() { >> doSomethingWithList(happensAfter); >> } >> }).start(); >> } >> >> And I understand now that by virtue of assigning to the final in the >> Runnable, that makes the call to add happen before. >> >> If that's correct, then I feel pretty confident that I get all this. > > Hmm... > > JLS Ch 17 says that... > > A call to start() on a thread happens-before any actions in the started > thread. > > Which implies that the final member of the runnable is unnecessary since > the item was added to the array before calling Thread.start and the run > method of the runnable will happen after thread start. Of course. Furthermore, any use of Runnable through a thread-safe API is going to ensure that whatever happens during the initialization in the Runnable has completed prior to the use of the Runnable itself. The trivial case is, of course, using the Runnable in the same thread where it's created. That's obviously true. But even in the case where the Runnable is being used in a different thread � that is, some other thread will get the reference and call the run() method � then as long as the Runnable is passed to that thread in a thread-safe way (and it had better be), there is necessarily some synchronization that ensures the Runnable reference has been passed safely. That same synchronization will establish the "happens-before" relationship required to ensure that the initialization of the Runnable, and indeed anything that happens before the reference is passed to the thread, is visible to any code in the other thread that executes after it has retrieved the reference to the Runnable. You may notice the similarity to the previous discussion regarding the invoke�() methods for use with the EDT. :) Pete
From: Lew on 21 Jul 2010 00:34 On 07/20/2010 11:10 PM, Alan Gutierrez wrote: > Joshua Cranmer wrote: >> On 07/20/2010 10:06 PM, Alan Gutierrez wrote: >>> It was all the talk about the importance of immutability that made me >>> worry that field assignments that were unsynchronized or non-volatile >>> could be hidden from the receiving thread. This bit of documentation >>> that I missed, plus a first reading of JLS Ch 17, put that to rest. >> >> Immutability is the easiest way to guarantee safe publication: final >> fields guarantee that they can be used by any thread safely. Any other >> type of object has to be safely published. Java Concurrency in >> Practice lists four ways of doing it: >> * Initializing an object reference from a static initializer >> * Storing a reference to it into a volatile field or AtomicReference >> * Storing a reference to it into a final field of a properly >> constructed object >> * Storing a reference to it into a field that is properly guarded by a >> lock. >> >> It also mentions that Java's thread-safe libraries all constitute safe >> publication, because of their internal synchronization. To be clear, >> the following are explicitly mentioned: >> Hashtable, Collections.synchronizedMap, ConcurrentMap, Vector, >> CopyOnWriteArrayList,CopyOnWriteArraySet, >> Collections.synchronizedList, Collections.synchronizedSet, >> BlockingQueue, and ConcurrentLinkedQueue. >> >> One key thing to note is that this safe publication only guarantees >> visibility of changes made to an object before publication; anything >> that happens afterwords must still be handled using regular >> thread-safety techniques. > > Very cool. Thank you. > > I recall seeing something like this earlier today. > > public void foo(int number) { > final List<Integer> list = new ArrayList<Integer>(); > list.add(number); > new Thread(new Runnable() { > final List<Integer> happensAfter = list; > public void run() { > doSomethingWithList(happensAfter); > } > }).start(); > } > > And I understand now that by virtue of assigning to the final in the > Runnable, that makes the call to add happen before. > > If that's correct, then I feel pretty confident that I get all this. Almost. Both the initialization of 'list' and the 'add()' to it /happen-before/ the call to 'doSomethingWithList()', so you could more compactly write: public void foo( int number ) { final List <Integer> list = new ArrayList <Integer> (); list.add( number ); new Thread( new Runnable() { public void run() { doSomethingWithList( list ); } }).start(); } on account of <http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4.5> "A call to start() on a thread happens-before any actions in the started thread." The local variable 'list' must be final to be accessible to the inner class. Be very careful with auto(un)boxing. -- Lew
From: markspace on 21 Jul 2010 01:42 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'm re-reading JCIP because of all the discussion here, and there's stuff in there I missed that first time around. It's intersting to re-read that book. Short answer is that a full discussion of immutability and thread safety is really hard in a forum where we're limited by how much we can type. Get the book, it's well worth it.
From: markspace on 21 Jul 2010 01:52
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. > 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. 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? |