![]() ![]() The reentrancy rules in the javadocs allow a thread that has the write lock to acquire the read lock without blocking. So what about the possibility of these two threads blocking each other? I don't think that is possible. and there was a circularity in the blocking. It would only be a deadlock if that third thread was itself waiting on a different lock. If some other thread currently held the write lock, that would be sufficient to block both of these threads. Now if no threads currently holds any locks, then one of these threads would be able to proceed. The other is waiting to acquire the write lock. One thread is waiting to acquire the read lock. The stack dump shows two threads waiting on the same ReentrantReadWriteLock. At least, not in the classic sense of the term. I don't think this is evidence of a deadlock. That I found by analyzing the code, and adding tracking and logging when the lock was acquired and released. Ultimately it was caused by a bug, in which a reader thread would not properly release the lock, and keep it forever. It was blocked on something entirely different, which would have required one of the other reader threads to progress. In this case the thread holding the lock was one of the reader threads. firstReaderHoldCount is firstReader's hold count.More precisely, firstReader is the unique thread that last changed the shared count from 0 to 1, and has not released theread lock since then null if there is no such thread. The firstReader field of the sync object contains the thread that have acquired the read log - from the comment in the code firstReader is the first thread to have acquired the read lock.Going through it I found the writer-0 and 7 of the 8 reader-n threads, confirming what we know from the thread dump. It is a queue, with thread containing the waiting thread, and next containing the next node in the queue. You can see the threads waiting for the lock in the head field.From this we can see that there's 1 shared hold and 0 exclusive holds on the lock. The exclusive holds count is in the last 16 bits, and is retrieved as state & ((1 << 16) - 1). The shared holds count is stored in the first 16 bits of the state, and is retrieved as state > 16. This represents both the number of shared and exclusive holds of the lock. In particular the sync field of that lock keeps its state - in this case it was ReentrantReadWriteLock$FairSync. I inspected the ReentrantReadWriteLock object kept in a field in the class.Thankfully, there were only a few instances of that class, so I was able to find the one that was causing problems.I double-clicked on the class to be taken to the "Instances" view.In the "Classes" view I filtered by the class name of the class that contains the lock as a field.I opened it using Java VisualVM, which comes with JDK.A heap dump was taken at roughly the same time as the thread dumps.For those interested in how, here's the process step-by-step: ![]() The only way to understand that was to inspect a heap dump of the application. The thread holding the lock was not reported as holding any locks in the thread dump, which made it difficult to diagnose. ![]() What else could be causing this behaviour? Is this a deadlock? I see that there is some change in the threads' state, but it could only be internal to the lock implementation. Taking a thread dump 4 seconds later yealds the same result, but all threads now report parking to wait for, which is different than 0x00000002b8dd4ea8 in the first dump.I can't find another thread that could possibly be holding the same lock.This looks like a deadlock, however there are a couple of things that make me doubt that: Reader: "reader-1" #249 daemon prio=5 os_prio=0 tid=0x00007f895000c000 nid=0x33d6 waiting on condition Īt .AbstractQueuedSynchronizer.doAcquireShared(AbstractQueuedSynchronizer.java:967)Īt .AbstractQueuedSynchronizer.acquireShared(AbstractQueuedSynchronizer.java:1283)Īt .ReentrantReadWriteLock$ReadLock.lock(ReentrantReadWriteLock.java:727) parking to wait for (a .ReentrantReadWriteLock$FairSync)Īt .LockSupport.park(LockSupport.java:175)Īt .AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)Īt .AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)Īt .AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)Īt .ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:943) This is on Java 8.īefore killing it someone took thread dumps, which look like this: It froze for about an hour, producing no log output and not responding to requests. I have an application with 1 writer thread and 8 reader threads accessing a shared resource, which is behind a ReentrantReadWriteLock. ![]()
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |