|
|
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 5 of 6
The fact that a simple synchronization strategy is used by publish_blocking causes an additional problem in the blocking-notification scenario: the entire Publisher is locked while the subscription_list is being accessed (for the entire period required for notifications). The entire object doesn't have to be locked, however.
We're synchronizing only to make access to the synchronization_list thread-safe. What we really need are two locks, one that guards the subscription_list and another that guards any other fields that we might choose to add to the Publisher. This way you couldn't add or remove subscribers while notifications were in progress, but you could call other synchronized methods of the Publisher class without blocking.
Three approaches to introducing a second lock come to mind. First, I could introduce a second lock using the roll-your-own Mutex class discussed in installment three of the current threading series. This solution is implemented in Listing 5.
|
A Mutex is really overkill in the current situation, however. A second approach encapsulates my original Publisher (from Listing 3) into a container class. I've done this in Listing 6. Now subscribe and related methods aren't synchronized at all, but chain through to their synchronized cousins in the contained Subscriber(). That is, the lock associated with the contained Publisher object controls access to the subscription_list and the lock associated with the container (Wrapped_publisher) object is used by other synchronized methods. The other_method() method (Listing 6, line 19), which is synchronized, locks the container, not the Publisher.
|
A third approach is to use the synchronized version of the LinkedList class, and then synchronize on the LinkedList itself. I've done that in Listing 7. Rather than creating a simple LinkedList on line 7, I've used Collections.synchronized() to wrap my list in an adapter, all of whose methods are synchronized. Now, I don't have to synchronize subscribe() or cancel_subscription(), and I don't have to synchronize when making the copy in publish(). However, I do have to explicitly synchronize on line 28 when I iterate across the list. This last approach is, I think, the most workable in practice, since it's the simplest to
implement.