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 4 of 6
|
Returning to Listing 3, you'll note that subscribe() and cancel_subscription() are synchronized, but publish() is not. Also note that publish() makes a copy of the subscription_list (on line 20) and notifies the subscribers by traversing the copy. This strategy is the one suggested in the JavaBeans specification for
handling notifications in a multithreaded environment, the point being that you don't want to lock up synchronized methods
of a publisher class while notifications are in progress. In any event, the new Java 2 Collection classes are (deliberately) not synchronized, so, subscribe() and cancel_subscription() must be synchronized in case one thread is trying to add a subscriber while another is removing one, or if two threads are adding
at the same time, and so on. (Yes, I know about the wrappers. I'll talk about them in a moment.)
Next, there is no way to tell how long it will take for a subscriber's receive() method to execute, since it's supplied by whoever implements the subscriber. Consequently, publish() executes for an indeterminate amount of time. If publish() were synchronized, then the entire object would be locked until the notifications completed. Any thread that attempted to
add or remove a subscriber, or call any other synchronized method for that matter, would block. So, publish() is not synchronized.
This lack of synchronization means that publish can't use the subscription_list directly, however. Otherwise another thread could come along and add and remove elements while notifications were in progress,
perhaps corrupting the Collection used for the subscription_list. The problem is solved simplistically by synchronizing long enough to make a clean copy, then working from the copy.
Even though this notify-from-the-copy strategy is recommended by Sun, it's not ideal. First, what if a subscriber is removed
from the list after the copy is made but before the notifications begin? The subscriber will be notified, even though it thinks
it has cancelled the subscription. This problem exists in all AWT/Swing listeners, and there is no easy solution -- never
assume that you will not be notified simply because you've removed yourself as a listener. To eliminate this problem, I've
included a second, synchronized, notification method in the Publisher: publish_blocking() (Listing 3, line 27). Since this version is synchronized, nobody can add or remove listeners while notifications are in process. I don't know
if this behavior is better than the nonblocking solution, but it's certainly different and more appropriate in some scenarios.
Note that the publish_blocking() doesn't have to copy the subscription_list since it synchronizes access to it -- it can just use an iterator to traverse the list.