我试图了解Locked ownable synchronizers线程转储中指的是什么?
Locked ownable synchronizers
我开始使用ReentrantReadWriteLock一个处于WAITING状态的线程,等待ReentrantReadWriteLock$FairSync另一个处于WAITING状态(a ThreadPoolExecutor)的线程的“锁定的拥有者同步器”列表中。
ReentrantReadWriteLock
WAITING
ReentrantReadWriteLock$FairSync
ThreadPoolExecutor
我找不到太多有关此的信息。它是某种“传递到”线程的锁吗?我试图找出死锁的来源,并且看不到任何线程正在主动锁定死锁(即- locked <0x...>在任何堆栈跟踪中都没有锁定)。
- locked <0x...>
TL; DR:写锁出现在“拥有的同步器”列表中,而 读锁则没有 。
我最终获得了以下MVCE,以尝试了解“可拥有的同步器”的含义。这个想法是让两个线程锁定/解锁读/写可重入锁,并查看在不同时间对不同线程转储的影响(在jVisualVM中拍摄,而Eclipse项目在特定行的断点处暂停)。
这是代码:
package lock; 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(); } } }
这是输出:
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)
现在,线程转储。
当线程“ main”获得读锁时,将执行线程转储#1。如我们所见, 线程没有任何“拥有的同步器” :
"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
线程转储#2是在线程“其他”获得了写锁之后进行的。它出现在“拥有的同步器”中:
"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)
线程转储#3在线程“其他”释放写锁定(并终止)并且线程“主”已获取它之后执行:
"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)
因此,写锁定将出现在“锁定的拥有者同步器”列表中,而读锁定则不会。即使getReadHoldCount()显示了当前线程已使用的读取锁的数量,读取的“锁定”似乎也不属于特定线程,因此不在列表中。这使得调试死锁变得很困难(或者说“不像使用jVisualVM那样容易”)。
getReadHoldCount()
编辑:为了帮助弄清楚复制/粘贴错误,并带有未释放的锁,例如:
myLock.readLock().lock(); try { // ... } finally { myLock.readLock().lock(); // Oops! Should be "unlock()" }
您可以在源目录的根目录下使用以下Linux命令行:
find . -name '*.java' -exec grep -Hn 'myLock.readLock().lock();' {} \; | wc -l
将显示已 采取 了多少个读取锁定,并且:
find . -name '*.java' -exec grep -Hn 'myLock.readLock().unlock();' {} \; | wc -l
将显示 释放 了多少个读锁。如果数字不匹配,请删除| wc -l以显示文件名(grep -H)和行号(grep -n)的详细信息。
| wc -l
grep -H
grep -n