public class CheckThenAct {
/**
* Unbound shared message queue;
*/
private final ConcurrentLinkedQueue<String> q;
/**
* Flag indicating whether operation should proceed;
*/
private final AtomicBoolean proceed = new AtomicBoolean(true);
public CheckThenAct(ConcurrentLinkedQueue<String> q) {
this.q = q;
}
public boolean putMessage(String msg) {
return proceed.get() ? q.offer(msg) : false;
}
public boolean stop() {
return proceed.compareAndSet(true, false);
}
}
In the putMessage() method we have "check-than-act" concurrency problem. I.e. when in thread1, thread2, ..., thread20 we pass proceed.get() but just right after that in thread23 we call stop(), i.e. no more messages, seriously; but in fact twenty messages being added to the q. Since putMessage() must be highly concurrent I can't make it(and stop()) synchronized. Solution is - to use RRWL:...
private final ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
...
public boolean putMessage(String msg) {
if (!rw.readLock().tryLock())
return false;
try {
return proceed.get() ? q.offer(msg) : false;
} finally {
rw.readLock().unlock();
}
}
public boolean stop() {
rw.writeLock().lock();
try {
return proceed.compareAndSet(true, false);
} finally {
rw.writeLock().unlock();
}
}
Let me explain why:- Read lock in putMessage() doesn't bring serialized behaviour, method still is highly concurrent;
- Read lock being acquired only when there is no write lock;
- Write lock being acquired only when there are no read locks;
- Write lock is exclusive;
So, main demand satisfied - truly shared access in putMessage() and remedy the "check-then-act" behaviour!
Thanks for reading!
No comments:
Post a Comment