From: Knute Johnson on 11 Mar 2010 00:49 On 3/10/2010 8:39 PM, John B. Matthews wrote: > In article<WXWln.10092$QL4.95(a)newsfe24.iad>, > Knute Johnson<nospam(a)rabbitbrush.frazmtn.com> wrote: > >> On 3/10/2010 3:07 PM, John B. Matthews wrote: >>> In article<S9Sln.90254$Ye4.78776(a)newsfe11.iad>, >>> Knute Johnson<nospam(a)rabbitbrush.frazmtn.com> wrote: >>> >>>> On 3/10/2010 10:34 AM, markspace wrote: >>>>> Knute Johnson wrote: >>>>>> Does anybody know if the Observable/Observer calls to update() are on >>>>>> the EDT? >>>> >>>>> Considering that Observer is just an interface and it would >>>>> depend on the implementation, and that no Java Swing classes that >>>>> I know of actually implement Observer, I'd have to guess the >>>>> answer is in general "no." >>>> >>>> The Observable class method, notifyObservers() is called and that >>>> then calls all Observer.update() methods. I'm curious to know if >>>> the Observable puts those calls onto the EDT. >>> >>> As markspace has elaborated, the answer is no. Not long ago, I >>> proposed that on Observable can invoke notifyObservers() on the >>> EDT, as via javax.swing.Timer, but access to any data shared >>> between threads must still be correctly synchronized. I found this >>> discussion very helpful >>> >>> <http://groups.google.com/group/comp.lang.java.programmer/browse_frm/thread/4c4a6b46ffd2d31f> >>> >>> and I have tried to express my understanding in this example: >>> >>> <http://sites.google.com/site/drjohnbmatthews/threadwatch> >> >> I looked through the source code and all of the methods of Observable >> are synchronized on the Observable instance. So threads that read >> any argument that is passed in and stored needs to be synchronized as >> well. I'm not sure how to do that. The whole point of using >> Observer/Observable is to disconnect the two classes. > > Interesting. The synchronized block in notifyObservers() mentions two, > worst-case potential races: 1) a newly-added Observer will miss a > notification in progress, and 2) a recently unregistered Observer will > be wrongly notified when it doesn't care. Unfortunately, the API doesn't > mention being synchronized. > >> Calling notifyObservers() from a known thread could be used to >> synchronize via thread containment but the docs imply that the >> calling thread isn't necessarily guaranteed to be the writing thread >> in the future. > > I read the Observable API as "but subclasses [of Observable] may ... > deliver notifications on separate threads." > >> In the application that I am writing, I am passing an Integer). In >> the Observer.update() method I store that Integer. I'm storing it in >> a volatile int so that solves the visibility problems for the reading >> thread but what if you had a mutable Object to pass? > > I'm not sure about that. > I'm thinking now that maybe I didn't design this quite correctly. -- Knute Johnson email s/nospam/knute2010/
From: markspace on 11 Mar 2010 01:01 Knute Johnson wrote: > On 3/10/2010 8:48 PM, Peter Duniho wrote: >> If the mutable Object was thread-safe, then it would handle that. >> Otherwise, you'd have to use some mechanism for ensuring >> synchronization. As far as I know, Java doesn't have an explicit memory >> barrier API, so "synchronized" is probably the best approach for simple >> mutation observability issues. >> >> Pete > > And there's the rub. If you have as in my case, two separate classes, > where you don't want to share data other than that which is shared via > the Observable/Observer, how do you get the Observable instance in the > Observer to then use to synchronize with? You have to assume that a > different thread could read the data after it was stored via the > Observer.update() method. > What are you trying to do? Are you trying to pass data between threads, or are you actually trying to implement an Observer Pattern? If you're implementing an Observer, you should probably take care to synchronize yourself, since the Observer really doesn't guarantee synchronization. If you're just looking for a memory barrier API, I think several classes in java.util.concurrent guarantee synchronization explicitly. This includes lock objects, executors, concurrent collections and probably a few others. This might be as simple as dumping the data into a BlockingQueue, and then reading it with a different thread.
From: Peter Duniho on 11 Mar 2010 01:14 Knute Johnson wrote: > On 3/10/2010 8:48 PM, Peter Duniho wrote: >> If the mutable Object was thread-safe, then it would handle that. >> Otherwise, you'd have to use some mechanism for ensuring >> synchronization. As far as I know, Java doesn't have an explicit memory >> barrier API, so "synchronized" is probably the best approach for simple >> mutation observability issues. >> >> Pete > > And there's the rub. If you have as in my case, two separate classes, > where you don't want to share data other than that which is shared via > the Observable/Observer, how do you get the Observable instance in the > Observer to then use to synchronize with? You have to assume that a > different thread could read the data after it was stored via the > Observer.update() method. Without a code example, it's hard for me to know for sure what you're talking about. However, if you are asking how to get the reference to the Observable instance so that you can use that reference in a "synchronized" statement, then the answer is "you don't, nor should you". Unless you specifically want to write some special thread-safe Observable sub-class that handles this, the synchronization isn't something the Observable needs to know about at all, nor would it be anything that needs the Observable instance itself. The synchronization is between the threads modifying the data and reading the data, while the Observable is just a by-stander. If you can provide a SSCCE that illustrates the relationship between your Observable, an Observer, and whatever other code exits that is modifying a mutable class instance, as well as examining that mutable class instance in a different thread, then surely a solution can be described that provides the necessary synchronization, but without necessarily making the Observable a central figure in that. Note that, depending on how strict you want to be about this whole "don't want to share data other than that which is shared via the Observable/Observer", you may require a wrapper class to impose the synchronization needed. But with an Observable that is not itself imposing a multi-threaded implementation, it's not at all clear how you managed to get two classes that know nothing of each other except for the Observable, and yet which are going to access the same data on two different threads. Either each class is associated with its own thread, and one knows about the other, or only one class includes code executing on two different threads (e.g. an Observer in one thread, and some other stuff in another), in which case it only needs to synchronize within itself. Basically, until it's clear how it is you've got an Observable that involves itself in cross-thread communication, in which two different threads involve two completely mutually-isolated classes except for an Observable mediating, and yet in which the Observable itself isn't involved in the threading, it's very hard to suggest a design that will work for you. After all, since the default Observable implementation simply calls update() in the same thread where notifyObservers() was called, how is it that the writer thread is different from the reader thread in the first place? I suspect that once you've focused on the answer to that question, you'll see the division between the two threads where the synchronization has to take place, and it probably will be simple to implement that synchronization independently of the Observable behavior. If you post a SSCCE, I'm sure you'll get good advice, if not from me then from someone else. :) Pete
From: Knute Johnson on 11 Mar 2010 01:18 On 3/10/2010 10:01 PM, markspace wrote: > Knute Johnson wrote: >> On 3/10/2010 8:48 PM, Peter Duniho wrote: >>> If the mutable Object was thread-safe, then it would handle that. >>> Otherwise, you'd have to use some mechanism for ensuring >>> synchronization. As far as I know, Java doesn't have an explicit memory >>> barrier API, so "synchronized" is probably the best approach for simple >>> mutation observability issues. >>> >>> Pete >> >> And there's the rub. If you have as in my case, two separate classes, >> where you don't want to share data other than that which is shared via >> the Observable/Observer, how do you get the Observable instance in the >> Observer to then use to synchronize with? You have to assume that a >> different thread could read the data after it was stored via the >> Observer.update() method. >> > > > What are you trying to do? Are you trying to pass data between threads, > or are you actually trying to implement an Observer Pattern? > > If you're implementing an Observer, you should probably take care to > synchronize yourself, since the Observer really doesn't guarantee > synchronization. > > If you're just looking for a memory barrier API, I think several classes > in java.util.concurrent guarantee synchronization explicitly. This > includes lock objects, executors, concurrent collections and probably a > few others. This might be as simple as dumping the data into a > BlockingQueue, and then reading it with a different thread. It would seem that there should be some method simpler than having to create a BlockingQueue to hand data between the Observable and the Observer. I have two classes that happen to be extensions of JPanels. Both of them have methods to input data that is then displayed (in various forms) on the other. The Observable/Observer appeared to be perfectly suited for this purpose. Then I got to thinking about which thread was being used and the fact that different threads could be writing/reading the data. That caused me to try to figure out how to synchronize that data between the classes. In my actual app, I write the data to a volatile int and that I'm sure will work but what if I needed to pass a reference to mutable object and wanted to ensure that the Observer had the latest information. So I'm sure the BlockingQueue would work but doesn't there have to be a simpler way? Or have I just designed this in a way that it was never intended to be? Thanks, -- Knute Johnson email s/nospam/knute2010/
From: Peter Duniho on 11 Mar 2010 01:22
markspace wrote: > Knute Johnson wrote: >> On 3/10/2010 8:48 PM, Peter Duniho wrote: >>> [...] As far as I know, Java doesn't have an explicit memory >>> barrier API, so "synchronized" is probably the best approach for simple >>> mutation observability issues. >> >> And there's the rub. If you have as in my case, two separate classes, >> where you don't want to share data other than that which is shared via >> the Observable/Observer, how do you get the Observable instance in the >> Observer to then use to synchronize with? You have to assume that a >> different thread could read the data after it was stored via the >> Observer.update() method. > > [...] > If you're just looking for a memory barrier API, I think several classes > in java.util.concurrent guarantee synchronization explicitly. [...] Note, as a minor point of clarification, that by "memory barrier", I mean specifically something that introduces a memory barrier for reads and writes, solely for the sake of the barrier rather than as part of some other synchronization construct (e.g. latch, atomic classes, etc.). Any synchronization object will implicitly include a memory barrier, but one can write lock-free code that still has a memory barrier to ensure coherency of data between threads. Though, frankly, it's hard to write lock-free code correctly (it's certainly not something I go around trying to do myself), and the "volatile" keyword can usually provide as much of a memory barrier as is needed. That is, you can ensure data is fully updated and visible by using a volatile variable as a gate-keeper…everything written before the volatile variable is written will be seen by any thread that reads that data after reading the volatile variable, as long as it reads the volatile variable after it was written. In other words, if the reading thread sees the change to the volatile variable, it will necessarily also see all changes to any data that happened before the volatile variable was written. Pete |