I want to submit tasks to a ForkJoinPool or ParallelArray from a thread holding a write lock. Access to our domain model is protected by checks that the current thread holds the relevant lock. To allow FJ workers to perform tasks on it (read only, e.g. querying), they need to delegate access checks to the thread that spawned them.
I subclassed the ForkJoinWorkerThread with a reference to the spawning thread. I then subclassed ReentrantReadWriteLock and overrode isWriteLockedByCurrentThread to perform the usual check, and fall back to a check that, if the thread is an instance of the delegating FJWorker, that the delegate thread (parent) is the owner of the lock, using ReentrantReadWriteLock#getOwner():
public class DelegateAwareReentrantReadWriteLock extends ReentrantReadWriteLock {
@Override
public boolean isWriteLockedByCurrentThread() {
return super.isWriteLockedByCurrentThread() || isWriteLockedByDelegateThread();
}
private boolean isWriteLockedByDelegateThread() {
final Thread currentThread = Thread.currentThread();
if (currentThread instanceof FJAccessDelegatingWorker) {
final Thread delegate = ((FJAccessDelegatingWorker) currentThread).getDelegate();
return delegate.equals(getOwner());
}
return false;
}
}
However, the documentation for getOwner() states the following:
When this method is called by a
thread that is not the owner, the return value reflects a
best-effort approximation of current lock status. For example,
the owner may be momentarily null even if there are
threads trying to acquire the lock but have not yet done so.
I would like to understand this to mean that if I’ve submitted the tasks within a thread that has already been granted access, this method will correctly return the reference to it. Unfortunately, this is not even implied.
If I can’t use this method, what other alternatives exist for this kind of delegation?
Thank you.
I imagine that the implementation details of getOwner() are such that if there is a happens-before relationship between the thread that acquired the write lock and the thread querying the owner, that it will have determinstic behaviour that ensures the correct owner is returned. I have not checked the implementation, but it feels like this is what the comments are alluding to, and are covering the base that the behaviour can be non-deterministic while the lock is being acquired.
However, it may be easier all around if it is possible for you to downgrade your write lock and avoid all of the delegation checking to begin with (since then each thread could own its own read lock). Perhaps it is also possible to use two separate locks, say an outer and inner lock, where the inner lock is not held for writing in this case?
Edit:
The implementation of getOwner() calls getState() which does a read of the volatile state variable, and this should be enough to guarantee that getOwner() will always return your parent thread if it holds the write lock.