How does the piggybacking of current thread variable in ReentrantLock.Sync work?
You suspect there could be a race between owner = current;
(after the CAS) and if (current == owner)
(after reading the state and checking if it is >0).
Taking this piece of code in isolation, I think your reasoning is correct. However, you need to consider tryRelease
as well:
123: protected final boolean tryRelease(int releases) {
124: int c = getState() - releases;
125: if (Thread.currentThread() != getExclusiveOwnerThread())
126: throw new IllegalMonitorStateException();
127: boolean free = false;
128: if (c == 0) {
129: free = true;
130: setExclusiveOwnerThread(null);
131: }
132: setState(c);
133: return free;
134: }
Here the owner is set to null
before the state is set to 0. To initially acquire the lock, the state must be 0, and so the owner is null
.
Consequently,
- If a thread reaches
if (current == owner)
withc=1
,- it can be the owning thread, in which case the owner is correct and the state is incremented.
- it can be another thread, which can see or not the new owner.
- If it sees it, everything is fine.
- If not, it will see
null
, which is fine as well.
- If a thread reaches
if (current == owner)
withc>1
,- it can be the owning thread, in which case the owner is correct and the state is incremented.
- it can be another thread, but the owner will be correct for sure.
I aggree that the footnote "read the owner field only after calling getState and write it only before calling setState" in JCIP is misleading. It writes the owner
before calling setState
in tryRelease
, but not tryAcquire
.