What is “Blocked Managed Synchronizers” in a stream dump?

I'm trying to figure out what Locked ownable synchronizers means in a thread dump?

I started using ReentrantReadWriteLock in a thread in WAITING state, waiting for the ReentrantReadWriteLock$FairSync in a "locked managed synchronizer" list of another thread in WAITING state (a ThreadPoolExecutor ).

I could not find much information about this. Are these some kind of locks that “switched” to a thread? I’m trying to find out where my deadlock is from, and I don’t see a single thread actively blocking it (i.e. Corresponding - locked <0x...> in any stack trace).

+6
source share
3 answers

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)"); // Take thead dump #3 here ("main" has a write lock, "other" has died) lock.writeLock().unlock(); } static class Th extends Thread { Th() { super("other"); } public void run() { System.out.println(Thread.currentThread().getName()+": read hold "+lock.getReadHoldCount()+" read lock "+lock.getReadLockCount()); if (!lock.writeLock().tryLock()) System.out.println(Thread.currentThread().getName()+": cannot lock write"); else { System.out.println(Thread.currentThread().getName()+": lock write taken"); lock.writeLock().unlock(); } System.out.println(Thread.currentThread().getName()+": trying to unlock read lock"); try { lock.readLock().unlock(); System.out.println(Thread.currentThread().getName()+": successfully unlocked read lock. Read hold "+lock.getReadHoldCount()+" read lock "+lock.getReadLockCount()); } catch (IllegalMonitorStateException e) { System.out.println(Thread.currentThread().getName()+": cannot unlock read lock: "+e.getMessage()); } synchronized (LockTest.class) { System.out.println(Thread.currentThread().getName()+": notifying write lock take (=>Thread dump #1)"); LockTest.class.notify(); // Take thead dump #1 here ("main" has a read lock) } System.out.println(Thread.currentThread().getName()+": locking write lock"); lock.writeLock().lock(); System.out.println(Thread.currentThread().getName()+": unlocking write lock (=>Thread dump #2)"); // Take thead dump #2 here ("other" has a write lock) lock.writeLock().unlock(); } } } 

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 #1) other: locking write lock main: unlocked read lock. Read hold 0 read lock 0. Getting write lock other: unlocking write lock (=>Thread dump #2) main: got write lock. Unlocking (=>Thread dump #3) 

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 ).

+4
source

From Java 7 Documentation :

A native synchronizer is a synchronizer that can be exclusively owned by a thread and uses the AbstractOwnableSynchronizer (or its subclass) to implement its synchronization property. ReentrantLock and ReentrantReadWriteLock are two examples of managed synchronizers provided by the platform.

+4
source

Proper use of ReentrantLock is not as easy as it sounds. It has several pitfalls. If we are talking about dead ends, I think you need to know:

one.

The main explanation we found at this point is the use of REETANTLOCK READ locks. Usually reading locks are not used intended to represent the concept of ownership. Since there is no record that contains a read lock, this seems to prevent the use of the HotSpot JVM lock detector logic to detect a deadlock involving read locks.

Some improvements have been implemented since then, but we see that the JVM still cannot detect this particular deadlock scenario.

From a good Java article on concurrency: hidden thread locks "

If you have access to the source code getReadHoldCount () , the method can help in detecting deadlocks.

2. The correct upgrade from readLock to writeLock - Java ReentrantReadWriteLocks - how to safely get a write lock?

+1
source

Source: https://habr.com/ru/post/1013465/


All Articles