Hi,
I apologize if i appear to be becoming lazy; is it bad form not to completely
read through your post; if so, I'm sorry.
I also have not looked through all the code. But, I will take one part of the
above and comment on it to exercise my mind. Please keep in mind that
threading is tricky, and I can easily make a mistake in what I assert to be
true.
WARNING: this is not production quality code, but it is quite sufficient
to exercise one's mind in threading:
These few lines of code seem logically correct, so I assume that this is
not an exercise from the book where there are problems lurking with
the code:
I have changed method and variable names to make it easier to parse:
While it's true that you can certainly take things out of the code, and
by liberally applying the yield() method, attempt to get a failure, it
also is just as important to be able to look at the code and come to
a determination as to its correctness, since it is quite possible that
during
testing you won't be able to create any noticable errors:
It is assumed that this lock() method is multithreaded. So, you need to ask
how the synchronization "binds" the logical lines of code together to prevent
another thread from interrupting the current thread and getting illogical
results.
So, between lines 3 and 4, if the current thread is paused, another thread
could come in and modify guardVector in some way that you don't anticipate
or don't want to happen. For instance, what if another thread removed
the target record number from the guardVector; then the thread that had
initially thought the target record was in the vector, would unnecessarily
wait(); this may or may not be critically important, you'd have to analyze
it more.
But, generally speaking, it makes logical sense to bind lines 3 and 4
together into a logical, atomic operation: a test on a vector which can't
change and then an action on a vector which didn't change. This is not
over synchronization.
Now, assume that the current thread is exiting the while loop and is now at
the comment line number 6. It's next job is to add a record number to the
vector. What happens if at line number 6 the current thread is spliced out
and another thread starts running. If the guardVector were not synchronized,
then another thread might add the same record number into the vector the
current thread was about to add; you might then have two threads thinking
they hold a lock on the same record (again, I have not written this down in
detailed proof, it is just an overview).
So, you have another logical binding: you don't want the object, the guardVector
to change during the steps that you decide it does not hold the record number
you wish to mutate, and the step that you actually add that record to the
guardVector.
In conclusion, the above is simply an example of multiple threads sharing an
object. If the current thread is basing any action on any assumption about this
shared object--such as it's current size, whether it contains this or that--
then you must synchronize the object for these two steps, these two steps
cannot have any other thread intervene:
synchronize (myObject) {
Step 1: Query object: i.e., "make assumptions before taking action"
Step 2: Take action based upon "these assumptions"
}
For a more detailed, step by step approach to learning about threads,
see Bruce Eckel's web site, his free online book:
Thinking in Java
Thanks,
Javini Javono
[ February 19, 2004: Message edited by: Javini Javono ]