TL DR: write locks appear in the Available Synchronizers list; read locks do not .
As a result, I got the following MVCE to try to understand what’s happening with a “managed synchronizer”. The idea was to lock / unlock lock / unlock records for reading / writing and see the effect on different dumps of threads in different timings (taken in jVisualVM, while the Eclipse project was suspended at breakpoints on certain lines).
Here is the code (in the "lock" package):
public class LockTest { static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); public static void main(String[] args) { lock.readLock().lock(); System.out.println(Thread.currentThread().getName()+": read hold "+lock.getReadHoldCount()+" read lock "+lock.getReadLockCount()); new Th().start(); synchronized (LockTest.class) { try { LockTest.class.wait(); } catch (InterruptedException e) { } } lock.readLock().unlock(); System.out.println(Thread.currentThread().getName()+": unlocked read lock. Read hold "+lock.getReadHoldCount()+" read lock "+lock.getReadLockCount()+". Getting write lock"); lock.writeLock().lock(); System.out.println(Thread.currentThread().getName()+": got write lock. Unlocking (=>Thread dump #3)");
Here is the result:
main: read hold 1 read lock 1 other: read hold 0 read lock 1 other: cannot lock write other: trying to unlock read lock other: cannot unlock read lock: attempt to unlock read lock, not locked by current thread other: notifying write lock take (=>Thread dump
Now dump threads.
A dump of stream # 1 is taken when the "main" stream gets a read lock. As we can see, no “managed synchronizer” belongs to the stream :
"main" prio=10 tid=0x00007fea5c00d000 nid=0x1866 in Object.wait() [0x00007fea65bd5000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000007acf62620> (a java.lang.Class for lock.LockTest) at java.lang.Object.wait(Object.java:503) at lock.LockTest.main(LockTest.java:14) - locked <0x00000007acf62620> (a java.lang.Class for lock.LockTest) Locked ownable synchronizers: - None "other" prio=10 tid=0x00007fea5c0e0800 nid=0x1883 at breakpoint[0x00007fea3abe8000] java.lang.Thread.State: RUNNABLE at lock.LockTest$Th.run(LockTest.java:46) - locked <0x00000007acf62620> (a java.lang.Class for lock.LockTest) Locked ownable synchronizers: - None
A dump of stream # 2 is taken after the "other" stream has taken a write lock. It appears in "managed synchronizers":
"main" prio=10 tid=0x00007fea5c00d000 nid=0x1866 waiting on condition [0x00007fea65bd5000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007acf63278> (a java.util.concurrent.locks.ReentrantReadWriteLock$FairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:867) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1197) at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:945) at lock.LockTest.main(LockTest.java:18) Locked ownable synchronizers: - None "other" prio=10 tid=0x00007fea5c0e0800 nid=0x1883 at breakpoint[0x00007fea3abe8000] java.lang.Thread.State: RUNNABLE at lock.LockTest$Th.run(LockTest.java:51) Locked ownable synchronizers: - <0x00000007acf63278> (a java.util.concurrent.locks.ReentrantReadWriteLock$FairSync)
The dump of stream # 3 is taken after the "other" thread released the write lock (and died), and the "main" thread took it:
"main" prio=10 tid=0x00007fea5c00d000 nid=0x1866 at breakpoint[0x00007fea65bd5000] java.lang.Thread.State: RUNNABLE at lock.LockTest.main(LockTest.java:19) Locked ownable synchronizers: - <0x00000007acf63278> (a java.util.concurrent.locks.ReentrantReadWriteLock$FairSync)
Thus, write locks will appear in the list of “locked managed synchronizers” when there are no read locks. Although getReadHoldCount()
shows the number of read locks made by the current thread, reading “lock” does not seem to apply to a specific thread and therefore is not listed. And this makes it difficult to debug deadlocks (or let them say "not as easy as using jVisualVM").
EDIT: To help find out copy / paste errors with recordings that have been removed and not released, for example:
myLock.readLock().lock(); try { // ... } finally { myLock.readLock().lock(); // Oops! Should be "unlock()" }
you can use the following linux command line in the root directory of your source directory:
find . -name '*.java' -exec grep -Hn 'myLock.readLock().lock();' {} \; | wc -l
will display how many read locks have been completed , and:
find . -name '*.java' -exec grep -Hn 'myLock.readLock().unlock();' {} \; | wc -l
will display how many read locks are issued . If the numbers do not match, delete | wc -l
| wc -l
to show file name details ( grep -H
) and line number ( grep -n
).