Speaking of thread safety?

K

Knute Johnson

Does anybody know if the Observable/Observer calls to update() are on
the EDT?

Thanks,
 
M

markspace

Knute said:
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."


If you mean the Swing method update( Graphics ), that isn't related to
the Observer interface. All Swing methods are not thread safe unless
noted otherwise, and update(Graphics) isn't an exception, so I think you
can assume that any caller has done their homework and called it on the
EDT. Although if you are implementing it yourself, putting in an
assertion might be a wise idea.

assert SwingUtilities.isEventDispatchThread();
 
K

Knute Johnson

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

markspace

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


Again, since Observable has NO connection to Swing at all, I see no
reason that a rational person reading its Java doc would conclude that
Observable had anything to do with the EDT, Swing, or the price of tea
in China.

You do realize that Sun's Java doc shows all inheriting classes for any
given class, right? There are no classes at all in Sun's API that
extend Observable (read the Java doc for it), it's just a class for the
Observer Pattern than you can use yourself.

I think some classes may use Observable internally, but that's
different: private inheritance (Java style, via composition). Go read
the Java docs of the other class, Observable doesn't do anything at all
except what it says.
 
I

Ian Shef

Does anybody know if the Observable/Observer calls to update() are on
the EDT?

Thanks,

In java 1.6.0_17, NO, unless notifyObservers(...) is called on the EDT.
However, there is no guarantee, and the Javadoc specifically states that
subclasses of Observable may even deliver notifications on separate
threads.

The following sample program prints

1.6.0_17
Thread[main,5,main]
Thread[AWT-EventQueue-0,6,main]

for me, demonstrating that the update() calls are on the thread used for
notifyObservers(...). Your Java may be different.

Here is the sample program:

package testpack1;
import java.util.*;
import javax.swing.SwingUtilities;
public class OberverTest {
static void showThread(Observable1 o1) {
o1.change();
o1.notifyObservers();
}
public static void main(String[] args) {
// Create an Observer that prints the Thread used for update(...)
Observer observer = new Observer() {
@Override
public void update(Observable arg0, Object arg1) {
System.out.println(Thread.currentThread()) ;
}
} ;
final Observable1 observable = new Observable1();
observable.addObserver(observer);
System.out.println(System.getProperty("java.version"));
showThread(observable); // Notify from the main thread.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
showThread(observable); // Notify from the EDT.
}
});
}
}
// Define a minimally useful Observable
class Observable1 extends Observable {
public void change() {setChanged();}
}
 
J

John B. Matthews

Knute Johnson said:
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>
 
K

Knute Johnson

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.

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.

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?

Thanks,
 
J

John B. Matthews

Knute Johnson said:
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.
 
K

Knute Johnson

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

Knute Johnson

Knute Johnson said:
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.
 
M

markspace

Knute said:
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.
 
K

Knute Johnson

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,
 
K

Knute Johnson

Knute said:
[...]
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. [...]

Why is that? Where is the data coming from? Both JPanels should be
executing on the EDT, assuming you haven't explicitly introduced a new
thread to them (and IMHO that would not generally be a good idea…GUI
logic belongs in the EDT, and non-GUI logic doesn't belong in a GUI
object).

Pete

The point is that you can't according to the docs, guarantee that
Observable's call to update() is done on a particular thread.
 
K

Knute Johnson

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

Pete:

Good points and I think I have figured out how to do this. I have to go
to work this morning but I will post an SSCCE this evening.

Thanks very much to you and markspace for all the comments, sometimes
you need other perspectives to see clearly.
 
M

markspace

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


OK, and sorry if I appear to be dense, but I really don't understand.

You have to JPanels which need to "observe" each other (or some other
object). So you make each JPanel with an extra "observable" interface:

public class MyPanel extends JPanel { ...

I can't actually use observable here because I can't extend both JPanel
and Observable, but let's not dwell on that much, I don't think it
matters. So what you end up with is something a bit like the
ActionListener mechanism, which is just methods in the class

public class MyPanel extends JPanel { ...
public void addObserver( Observer o ) ...
public void removeObserver( Observer o ) ...
public void notifyObservers( Object message ) ...
}

Now you have two choices. You could add big Javadoc instructions to
only use these methods on the EDT. JPanels aren't thread safe to begin
with so maybe that wouldn't be so bad. However, as a design feature you
decide to allow these messages to be called from any thread. There are
a few Swing methods like that (setText() on the JTextComponent and
subtypes) which makes that method very convenient to use, so this may be
a good idea.

I think that's where I'm at. Did I follow correctly so far? I can see
two or three ways of implementing this, but it's complicated enough that
I don't want to make a large example if I haven't got the right
specification.

I'm thinking that it largely depends on what kind of guarantees YOU want
to make. That I think is the critical point. There's some kind of
guarantee or design consideration that you want to make, and everything
flows from there. Thread safety, and program correctness, just don't
happen, you have to figure out how to make them happen.

Anyway, I don't mean to rant. If I've understood it, I think I or
anyone else could give some advice on how to do this, given a correct
specification. Let me know if I've got it and I'll proceed from there.
 
K

Knute Johnson

This has been driving me for two days now and I had to get this out
before I left for the day.

Panel1 has a JSpinner that is used to acquire input. It uses a
ThreadSafeObservable to send that data to Panel2 where it is displayed.
I have deliberately used a new thread other than the EDT to do the
sending. This was easier than writing a Panel2 that used other than the
EDT to read the data but the point is the same, you can't guarantee that
the thread writing the data will be the same thread reading the data.
In the ThreadSafeObservable I synchronize on the ThreadSafeObserver when
calling update(). Then in Panel2's paintComponent() when I access the
stored value, I again synchronize on the ThreadSafeObserver using
'this'. This enforces the requirement that the same lock be used to
read and write the data. In this instance using a volatile for the
stored value would have worked even better but if I were sending some
arbitrary mutable object it wouldn't do.

If you look at Sun's source for Observable, you will see that the list
of Observers are stored in a private Vector. Because no method exist to
get at the Observers, overriding notifyObservers() becomes rather
difficult. I'm not sure if there is some underlying reason for this or
if it was just an oversight.

My SSCCE source code is below but I have put all of the files, including
Sun's source for the Observable and Observer on my web site here;

http://rabbitbrush.frazmtn.com/observable/

I would appreciate any comments or any possible risks that you see with
this approach.

Thanks,


package com.knutejohnson.test;

import java.awt.*;
import javax.swing.*;

public class Demo {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Thread Safe Observable Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setLayout(new FlowLayout());

Panel1 p1 = new Panel1();
Panel2 p2 = new Panel2();
p1.addObserver(p2);

f.add(p1);
f.add(p2);
f.pack();
f.setVisible(true);
}
});
}
}

package com.knutejohnson.test;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;

public class Panel1 extends JPanel {
private final ThreadSafeObservable observable;
private final JSpinner spin;

public Panel1() {
super(new GridBagLayout());

setPreferredSize(new Dimension(100,100));

observable = new ThreadSafeObservable();

spin = new JSpinner(new SpinnerNumberModel(0,0,100,1));
spin.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent ce) {
JSpinner s = (JSpinner)ce.getSource();
final int value = ((Integer)s.getValue()).intValue();
// start a different thread just to be sure
new Thread(new Runnable() {
public void run() {
observable.setChanged();
observable.notifyObservers(value);
}
}).start();
}
});

add(spin);
}

public void addObserver(ThreadSafeObserver o) {
observable.addObserver(o);
}
}

package com.knutejohnson.test;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

public class Panel2 extends JPanel implements ThreadSafeObserver {
private int value;

public Panel2() {
setPreferredSize(new Dimension(100,100));
}

public void update(ThreadSafeObservable o, Object arg) {
// store value here synchronized on this the observer
synchronized (this) {
value = ((Integer)arg).intValue();
}
repaint();
System.out.println(
"update() called from: " + Thread.currentThread().getName());
}

public void paintComponent(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(Color.BLUE);
// read value here synchronized on this
synchronized (this) {
g.fillRect(getWidth()/2-10,getHeight()-value,10,value);
}
System.out.println(
"paintComponent() called from: " +
Thread.currentThread().getName());
}
}

package com.knutejohnson.test;

import java.util.*;

public class ThreadSafeObservable {
private boolean changed = false;
private Vector obs;

public ThreadSafeObservable() {
obs = new Vector();
}

public synchronized void addObserver(ThreadSafeObserver o) {
if (o == null)
throw new NullPointerException();

if (!obs.contains(o)) {
obs.addElement(o);
}
}

public synchronized void deleteObserver(ThreadSafeObserver o) {
obs.removeElement(o);
}

public void notifyObservers() {
notifyObservers(null);
}

public void notifyObservers(Object arg) {
Object[] arrLocal;

synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();

for (int i=arrLocal.length-1; i>=0; i--)
// synchronize on the observer
synchronized (arrLocal) {
((ThreadSafeObserver)arrLocal).update(this,arg);
}
}
}

public synchronized void deleteObservers() {
obs.removeAllElements();
}

protected synchronized void setChanged() {
changed = true;
}

protected synchronized void clearChanged() {
changed = false;
}

public synchronized boolean hasChanged() {
return changed;
}

public synchronized int countObservers() {
return obs.size();
}
}

package com.knutejohnson.test;

public interface ThreadSafeObserver {
void update(ThreadSafeObservable o, Object arg);
}
 
M

markspace

I don't know if you had time to read my earlier reply, but after I
posted it I starting thinking about the little design I posted. I'm
thinking that what I said--that it is probably good design to allow a
thread safe method of the observer--is just wrong.

There's two competing principles in design: 1. usefulness or ease of
use, and 2. pithiness. The opposite of pithiness is gold plating, a
known anti-pattern.

If you over emphasize 1, then you risk a baroque, ornamented design that
takes 20 method calls to accomplish what should take just one method call.

If you over emphasize 2, then you risk a stark design that only works
for your particular need, but can't be extended and is difficult to
maintain due to it being too embedded in the particular code you wrote.
Always there's a balance to maintain.

Anyway, what I'm trying to say here is that because you have a JPanel to
begin with, you have events on the EDT anyway, so why not just skip the
thread safety and say all methods have to be called on the EDT?

For example:

Knute said:
Panel1 p1 = new Panel1();
Panel2 p2 = new Panel2();
p1.addObserver(p2);


This is EXACTLY the example I was going to provide, implemented on the
EDT just as you have. And it doesn't need to be specially thread safe,
it's naturally called on the EDT anyway.

Yes, making the classes not thread safe risks making the class hard to
use. But most Swing classes aren't thread safe, and folks are used to
dealing with that. So there's a well developed body of knowledge for
working with Swing classes that aren't thread safe, and I don't think
you're risking much by requiring the user be responsible for thread safety.

By contrast, especially after looking at your code, I think you are
risking a baroque, gold-plated, hard-to-maintain design by trying to
make the class totally thread safe. Events fire on the EDT because it's
fast to do so; trying to spawn a separate thread just to re-issue an
event to update your 2nd panel on the EDT again seems like mis-design.
(What one of my professors used to call "going around your elbow to get
from your forefinger to your thumb.")

Anyway, here's my design. I nixed your actual panel because it was just
easier to use a JTextArea for the example, but the whole thing fires on
the EDT, so it doesn't matter. It's all thread safe, and I don't have
to make any threads, and therefore things should happen quickly and the
UI should stay fast too. The code is shorter, and runs faster. Win-win.

(Note the JSpinner doesn't actually say that a ChangeListener is
guaranteed to be called on the EDT. I assume that it is. Therefore any
observer added can assume that it's update() method is also called on
the EDT, because of my design.)


Here's the main class, you can see it's pretty short and too the point:


package panelstest;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Main {

public static void main(String[] args) {
SwingUtilities.invokeLater( new Runnable() {

public void run()
{
createAndShowGui();
}
} );
}

private static void createAndShowGui() {

JPanel panel = new JPanel();
BoxLayout layout = new BoxLayout( panel, BoxLayout.PAGE_AXIS );
panel.setLayout( layout );

SpinnerPanel spinPan = new SpinnerPanel();
VariableRectanglePanel vrp = new VariableRectanglePanel();
spinPan.addOberver( vrp );

panel.add( spinPan );
panel.add( vrp );

JFrame frame = new JFrame("Oberver Test" );
frame.add( panel );
frame.setLocationRelativeTo( null );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );

}

}



The rest of the code is kinda baroque because I was lazy and used a GUI
editor to generate the panels, so they're nicely laid out. Phear the
code generator, I guess. If you suck these classes into an IDE and use
code-folding to hide the methods that have the auto-generated comment,
you'll see that they're very simple in concept. The code I had to add
is pretty easy.

First the easy bit, my observer interface:

package panelstest;

public interface MyObserver {
void update( Object message );
}


Now for the hold-your-nose bits:

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

/*
* SpinnerPanel.java
*
* Created on Mar 11, 2010, 1:18:21 PM
*/

package panelstest;

import java.util.ArrayList;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
*
* @author Brenden
*/
public class SpinnerPanel extends javax.swing.JPanel {

private ArrayList<MyObserver> observers = new ArrayList<MyObserver>();

/** Creates new form SpinnerPanel */
public SpinnerPanel() {
initComponents();
jSpinner1.addChangeListener( new ChangeListener() {
public void stateChanged( ChangeEvent e )
{
System.err.println( "EDT:
"+SwingUtilities.isEventDispatchThread() );
notifyObservers( jSpinner1.getValue() );
}
} );
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">

private void initComponents() {

jLabel1 = new javax.swing.JLabel();
jSpinner1 = new javax.swing.JSpinner();

setBorder(javax.swing.BorderFactory.createTitledBorder("Spinner
-- Observable"));

jLabel1.setText("Spin me! ");

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1)

..addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSpinner1,
javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(59, Short.MAX_VALUE))
);
layout.setVerticalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()

..addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(jSpinner1,
javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE,
Short.MAX_VALUE))
);
}// </editor-fold>


// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
private javax.swing.JSpinner jSpinner1;
// End of variables declaration

/** NOT THREAD SAFE! Call only on the EDT */
public void addOberver( MyObserver observer ) {
observers.add( observer );
}

private void notifyObservers( Object message ) {
for( MyObserver o : observers ) {
o.update( message );
}
}
}


------------And-------------

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

/*
* VariableRectanglePanel.java
*
* Created on Mar 11, 2010, 1:23:27 PM
*/

package panelstest;

/**
*
* @author Brenden
*/
public class VariableRectanglePanel extends javax.swing.JPanel
implements MyObserver {

/** Creates new form VariableRectanglePanel */
public VariableRectanglePanel() {
initComponents();
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {

jLabel1 = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea();


setBorder(javax.swing.BorderFactory.createTitledBorder("Variable
Rectangle -- Observer"));

jLabel1.setText("Variable Rectangle:");

jTextArea1.setColumns(20);
jTextArea1.setRows(5);
jScrollPane1.setViewportView(jTextArea1);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1)

..addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jScrollPane1,
javax.swing.GroupLayout.DEFAULT_SIZE, 245, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()

..addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1,
javax.swing.GroupLayout.DEFAULT_SIZE, 154, Short.MAX_VALUE)
.addComponent(jLabel1))
.addContainerGap())
);
}// </editor-fold>


// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration

public void update( Object message )
{
jTextArea1.append( "Update: "+message.toString()+"\n" );
}

}
 
K

Knute Johnson

I don't know if you had time to read my earlier reply, but after I
posted it I starting thinking about the little design I posted. I'm
thinking that what I said--that it is probably good design to allow a
thread safe method of the observer--is just wrong.

There's two competing principles in design: 1. usefulness or ease of
use, and 2. pithiness. The opposite of pithiness is gold plating, a
known anti-pattern.

If you over emphasize 1, then you risk a baroque, ornamented design that
takes 20 method calls to accomplish what should take just one method call.

If you over emphasize 2, then you risk a stark design that only works
for your particular need, but can't be extended and is difficult to
maintain due to it being too embedded in the particular code you wrote.
Always there's a balance to maintain.

Anyway, what I'm trying to say here is that because you have a JPanel to
begin with, you have events on the EDT anyway, so why not just skip the
thread safety and say all methods have to be called on the EDT?

For example:




This is EXACTLY the example I was going to provide, implemented on the
EDT just as you have. And it doesn't need to be specially thread safe,
it's naturally called on the EDT anyway.

Yes, making the classes not thread safe risks making the class hard to
use. But most Swing classes aren't thread safe, and folks are used to
dealing with that. So there's a well developed body of knowledge for
working with Swing classes that aren't thread safe, and I don't think
you're risking much by requiring the user be responsible for thread safety.

By contrast, especially after looking at your code, I think you are
risking a baroque, gold-plated, hard-to-maintain design by trying to
make the class totally thread safe. Events fire on the EDT because it's
fast to do so; trying to spawn a separate thread just to re-issue an
event to update your 2nd panel on the EDT again seems like mis-design.
(What one of my professors used to call "going around your elbow to get
from your forefinger to your thumb.")

Anyway, here's my design. I nixed your actual panel because it was just
easier to use a JTextArea for the example, but the whole thing fires on
the EDT, so it doesn't matter. It's all thread safe, and I don't have to
make any threads, and therefore things should happen quickly and the UI
should stay fast too. The code is shorter, and runs faster. Win-win.

(Note the JSpinner doesn't actually say that a ChangeListener is
guaranteed to be called on the EDT. I assume that it is. Therefore any
observer added can assume that it's update() method is also called on
the EDT, because of my design.)

Thanks for the code, the important parts were not that hard to read.

There are two issues that I was trying to solve using
Observable/Observer. First the docs for Observable say that the thread
calling Observer.update() may use a thread different from the one
calling Observable.notifyObservers(). "...but subclasses may change
this order, use no guaranteed order, deliver notifications on separate
threads..." So while Observable as it is currently written will deliver
notifications on the same thread as it was called from, that may or may
not be true later. If it isn't, the data may or may not be accessible
from another thread. Two, how to pass a message that was to be used in
multiple threads at the destination.

In my actual application that got me started down this path, I stored
the int in a volatile and everything is solved. The Observable could
use any thread, and the Observer could as well and my simple message is
fine. If I could be guaranteed that Observable would always call
notifyObservers() from the EDT and that I only wanted to use the data
from the EDT then there is no problem again. In my application I needed
to use the message data on the EDT and on another thread so I required
some sort of synchronization to guarantee that it would work.

If you are interested in the actual application, I have it running at:

http://rabbitbrush.frazmtn.com/aviation

Scroll to the bottom of the page and look at the VOR Trainer applet.
The source code is there as well.

So I still have one major question, how could one extend Observable and
modify notifyObservers() without access to the list of Observers? For
the example I had to re-create both Observable and Observer. Why would
Sun not have included a method to get the list of Observers?
 
J

John B. Matthews

<http://sites.google.com/site/drjohnbmatthews/threadwatch> [...]
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.[/QUOTE]

I have to acknowledge your clear SSCCEs and appealing demos.

I think writing your own Observer/Observable implementations gets around
the limitations of the Java 1.0 version. The hidden synchronized block
in notifyObservers() helps me understand why my demo works at all.
 
M

markspace

Knute said:
If I could be guaranteed that Observable would always call
notifyObservers() from the EDT and that I only wanted to use the data
from the EDT then there is no problem again. In my application I needed
to use the message data on the EDT and on another thread so I required
some sort of synchronization to guarantee that it would work.


As I mention, there is a large body of knowledge which folks learn to
deal with situations like this. What do you do with any listener which
is called on the EDT, when you want to run some portion of its code off
the EDT? One popular way is to use a SwingWorker. Easy, standardized,
and most people will instantly recognize the pattern and know what is
going on.

That's not to say what you did is wrong, just that there might be better
ways of doing what you did, by re-using existing classes and paradigms.

If you are interested in the actual application, I have it running at:

http://rabbitbrush.frazmtn.com/aviation

Scroll to the bottom of the page and look at the VOR Trainer applet. The
source code is there as well.


I haven't looked at this yet. If I get some time I will.

So I still have one major question, how could one extend Observable and
modify notifyObservers() without access to the list of Observers? For


Well, I think I did that in my code, minus the bit about extending the
Observable. The "notify" code starts on the EDT due to the JSpinner's
internals, and I just invoke each observer on the same thread.

I should probably add a assert to verify this, but I didn't make any
test harness so I didn't add any asserts...

the example I had to re-create both Observable and Observer. Why would
Sun not have included a method to get the list of Observers?


Beats me. They do allow you to get a list of PropertyChangeListeners,
which is the interface I ended up using (indirectly). Possibly it may
not be safe to allow an external user to get at the internals of a class
that wants to synchronize and protect it's private data, so there may in
fact be a good reason.
 

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

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top