Reputation: 247
I sometimes write code like:
Method 1:
synchronized (someMonitor) {
newInfo = true;
someMonitor.notifyAll();
}
Method 2:
synchronized (someMonitor) {
while (!newInfo) {
someMonitor.wait();
}
newInfo = false;
}
I imagine there's a higher-level concurrency object in the API to handle this. It should work like:
Method 1:
ensureFlagRaised();
Method 2:
blockUntilFlagRaisedThenLowerFlag();
I could use a BlockingQueue with capacity 1 to call the non-blocking offer(dummyElement) and the blocking take(). But this seems like an abuse of that class.
Any cleaner solutions?
Upvotes: 2
Views: 369
Reputation: 73528
There are several ways you can do this.
The most direct replacement would be to switch using Lock
and Signal
, which mimics closely the synchronized/wait/notify
mechanism.
But for a simple flag, the easiest approach is probably a Semaphore. With it, your example code could look like the following:
Semaphore s = new Semaphore(0, true); // No permits to start with, acquire will block
// Producer loop
makeNewDataAvailable();
s.release(); // Raise "flag" to indicate new info
possiblyDoSomethingUseful();
s.acquire(); // A fair semaphore, so waiting threads get the permit
// Consumer loop
s.acquire(); // Blocks until "flag" raised, then acquires it
processNewData();
s.release(); // Pass the permit back to thread 1
But Semaphore
does require you to plan your logic correctly, otherwise you could end up in a deadlock.
A producer/consumer situation is solved better with other mechanisms though, as you see the code can look confusing and you need to keep track of who's calling acquire/release
and when. The above code could be better implemented with for example Exchanger:
Exchanger<String> e = new Exchanger<>();
// Producer loop
e.exhange(generateNewData()); // Ignore consumer's response
// Consumer loop
processData(e.exchange(null)); // Get data, send dummy back
Upvotes: 4