Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 2 of 6
main() executes, popping up the main frame and setting the status message.main() finishes the first piece of work, and sends the messagemyself.change_status( "Done", "I'm done doing something");
to the main-frame object. This method is synchronized, so it appears safe.
change_status() (after the title is changed, but before the contents are changed) the user hits the "Show status" button. The main thread is preempted, and the AWT thread wakes up to process
the button press.A first (incorrect) attempt to solve the problem might be to synchronize the actionPerformed() method:
pop_it_up.addActionListener
( new ActionListener()
{ public synchronized void actionPerformed( ActionEvent e )
{ JOptionPane.showMessageDialog( null,
contents, title, JOptionPane.INFORMATION_MESSAGE );
}
}
);
This doesn't work, though. Remember, we have two objects and two monitors. Locking the inner-class object does not affect access to the outer-class object, which contains the two fields that are giving us grief. The only solution is to synchronize on the object that actually contains the fields that the two threads are accessing -- the outer-class object:
pop_it_up.addActionListener
( new ActionListener()
{ public void actionPerformed( ActionEvent e )
{ synchronized( Status.this )
{
JOptionPane.showMessageDialog( null,
contents, title, JOptionPane.INFORMATION_MESSAGE ); }
}
}
);
To be safe, all inner-class listeners that access outer-class fields should synchronize on the outer class object in this way.
Flipping the perspective over to that of the notifier, various thread-related problems emerge here, too:
Let's start by analyzing the modification-while-notifications-are-in-progress problem, which in some ways is the hardest to solve. AWT listeners can be added or removed at any time, even when notifications are in progress. In fact, a listener can even remove itself from a list of listeners as it services the notification message passed to it. The following code is perfectly legal:
Button some_button;
//...
some_button.addActionListener
( new ActionListener()
{ public void actionPerformed( ActionEvent e )
{ some_button.removeActionListener( this );
//...
}
}
);
I'll describe how to get control over this potentially chaotic situation by looking at various examples (which comprise this
month's entries in the world's-most-complicated-way-to-print-"hello world" contest). Listing 2 shows an implementation of the world's simplest observer/subscriber. The publication can be any arbitrary Object. (I don't like having to cast it all the time, but it's the price you pay for flexibility.) If you're interested in receiving
notices about something, you implement this interface, providing your own version of receive(), which is called when the event is fired off. In a more complex example, you might extend Subscriber with another interface that adds event-specific methods.