Due to the multithreaded nature of the Java language, classes must protect themselves by synchronizing critical methods in their implementations. Though use of synchronization can lead to a deadlock wait state, as in the following model-view example:
class
Viewer{
Model _model;
synchronized void paint (Graphics g)
{
doStuff();
Object data = _model.getData();
doMoreStuff();
}
}
class Model
{
Object _data;
synchronized Object getData () {return _data;}
synchronized void setData (Object d)
{
_data = d;
fireContentsChangedEvent();
}
void fireContentsChangedEvent()
{
viewer.contentsChanged (
new ContentsChangedEvent());}
}
postInit ()
{
model.setData (data);
}
1. paint() starts running in Thread A and is suspended at doStuff().
2. postInit() starts running in Thread B and yields at viewer.contentsChanged()
because Thread A has the viewer locked.
3. Thread A resumes and tries to call model.getData()...deadlock!
The key is to be aware of situations where multiple threads are interacting with the same components potentially resulting in undesirable deadlocks.
In the case of the model-view problem, several options are available from within a webAF applet. First note that the postinit method of the applet is executed in a different thread. This is done to maximize performance during startup. Secondly note that a viewer's paint method may be invoked and suspended at anytime. When adding code to the postinit method make sure the code is thread safe.
If code added to postinit is primarily there to initialize the model, it is recommended that you do not attach the model and view until after the initialization takes place. Rather than dropping the model on the view in the webAF development environment, wait until after you've initialized the model in postinit to attach the view. Adding the following line at the end of postinit should accomplish this.
/* Attach the model and view */
viewer.setModelInterface(model);
If the model and view have been attached, you may detach them using:
/* Detach the model and view */
viewer.setModelInterface(null);
Don't forget to reattach them after you have completed the interactions with the model.
Another solution is to put any dependent code in a synchronize statement.
synchronize( viewer )
{
synchronize(model)
{
add your code here
}
}
This will force one object to complete its execution before the other begins. Code within a synchronized statement will not execute until an exclusive lock on the object can be obtained. Note that the order of the synchronize statements is important and can often be tricky to predict. If you are fairly certain of the order in which the threads execute, this may be a viable solution.
In summary, be aware when multiple threads are interacting with the same components and take steps to prevent synchronization deadlocks.
For more information on thread safety see
http://www.javaworld.com/javaworld/jw-08-1998/jw-08-techniques.html