From: Peter Duniho on 21 Jul 2010 03:23 markspace wrote: > Lew wrote: > >> markspace wrote: >>> I agree that the only practical way to pass an object to the EDT >>> involves a shared lock. However, invokeLater() makes no such guarantee, >> >> Are you kidding? The whole documented point of 'invokeLater()' and >> 'invokeAndWait()' is to push things to the EDT in a thread-safe manner. > > > Addendum: no, I'm not kidding. Where do you see it documented that the > purpose of invokeLater() is to "push things" to the EDT? I only see it > documented that invokeLater() executes code, so that already existing > objects, created on the EDT, can be accessed in a thread safe manner. > > All the examples of using invokeLater() I can find carefully avoid any > access of objects created off the EDT, unless that object is made thread > safe some other way (e.g., use of final keyword). In general, the examples I've seen use "final" only because that's the only way to refer to a local variable in an anonymous class. It has nothing to do with "carefully avoiding any access of objects created off the EDT". The example that IMHO is _definitive_ would be the discussion found here: http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html And there's no example of any code there where any specific attempt is made to synchronize access to data initialized for use in the Runnable. Here's an excerpt that specifically _doesn't_ do synchronization: void printTextField() throws Exception { final String[] myStrings = new String[2]; Runnable getTextFieldText = new Runnable() { public void run() { myStrings[0] = textField0.getText(); myStrings[1] = textField1.getText(); } }; SwingUtilities.invokeAndWait (getTextFieldText); System.out.println(myStrings[0] + " " + myStrings[1]); } Now, the above is actually (according to you) "broken" in the other direction. That is, data is initialized in the EDT, and then used after the invokeAndWait() method returns, but no explicit synchronization is present to ensure that the data is visible in the original thread. But it's exactly the same issue you're talking about. If it's broken going from the original thread to the EDT (as you claim), it's also broken going from the EDT to the original thread. > If you can show documentation that even partially supports your claim, > I'd love to see it. If you can show documentation that even partially supports your claim, I'd love to see it. You'd think that if it were important to explicitly synchronize data initialized prior to calling one of the invoke…() methods when that data will be used in the Runnable, the documentation would actually mention that fact. The documentation that supports my claim (and Lew's, which is identical) is the JLS, where it describes the "happens-before" guarantees that are related to the use of the various synchronization techniques. Along with, of course, the documentation for the invoke…() methods, which promise that those methods will actually work. It would be nice if the JDK docs themselves distilled the admittedly more complicated presentation found in the JLS, to make it more clear to those less familiar with the JLS and concurrency issues in general. But the fact that it doesn't isn't proof of the invoke…() methods being broken. Regardless of the state of the documentation, as I have pointed out a number of times already, it is simply not possible for the invoke…() methods to work correctly and yet not ensure the necessary order of operations: • The invoke…() methods both take as an argument a reference to a Runnable instance • This reference _must_ be passed to the EDT somehow (after all, that's where the Runnable's run() method is going to be called), and the only way to achieve that in a thread-safe way is to synchronize some shared data between the two threads • The act of synchronizing shared data, even if simply by use of "volatile", _guarantees_ that any data written before the synchronized, shared data is written will be visible to any other thread that reads the data after the shared data is read Thus, everything that your non-EDT thread that calls the invoke…() method writes before that call is visible in the EDT from the moment the Runnable's run() method starts executing (actually, a bit before that, when the Runnable's reference was actually read, but there's no practical way to take advantage of that…for all intents and purposes, it's the stuff in and after the run() method that counts). There is simply no other way that it can work. The entire invoke…() paradigm would be fundamentally broken otherwise. Pete |