Re: Don't Understand wait() and notify()
Jason Cavett wrote:
The issue I am having, is I don't understand how wait and notify apply
in this case. I was initially attempting to use the FileProcessor
object as a lock.
The object that is used as a lock isn't really relevant. However, it's a
good idea to keep as much as possible private. That includes locks. So,
IMO it's generally best to use a dedicated lock object. As a little
trick you can use a nested (or local) class with the name Lock, to help
in stack dumps (more later). So:
private static class Lock { }
private final Object lock = new Lock();
When the FileWorkerThread started up, if nothing
was in the queue of the FileProcessor, the FileWorkerThread was
supposed to wait until there was something in the queue.
Unfortunately, when I called wait() on the FileProcessor object (the
one that I was synchronizing over) the GUI would hang.
The way to start to diagnose these problems is with a dump of all the
thread stacks. Type ctrl-\ (or ctrl-break in Windows) from the console,
use the jstack tool in recent JDKs or use a debugger.
If you want a blocking Queue, there is a ready made, high performance
solution in the form of java.util.concurrent.BlockingQueue and its
implementations.
public synchronized void notifyWorker() {
this.notify();
}
This is an obvious problem. You should set some state within the
synchronized block and then notify (or actually better is the other way
around).
Also you want to consider could this ever be used in a situation where
there is more than one thread waiting. If the answer is yes, or not
really sure, use notifyAll.
public synchronized void waiting() {
try {
this.wait();
this.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Again, the notify should only happen after some state change, and wait
should be in a while loop.
// work forever
while (true) {
// check for work
File file = processor.dequeueFile();
if (file == null) {
synchronized(processor) {
processor.waiting();
}
} else {
// do stuff here
}
}
There appears to be a race condition here. What happens if between the
dequeueFile and the synchronized, a file is queued?
Generally loops like this should look, for a non-blocking queue
implementation, something like:
for (;;) {
final File file;
synchronized (lock) {
while (queue.isEmpty()) {
lock.wait();
}
file = queue.poll();
}
... do stuff with file ...
}
P.S. At some point, I'm going to want to use the worker thread to
update a progress bar - I don't know if that'll affect anything or if
there's anything additional I will need to think about.
You should be in the Event Dispatch Thread to update any controls. Use
java.awt.EventQueue.invokeLater.
Tom Hawtin