使用reentrantreadwritelock时这是死锁吗?

wz1wpwve  于 2021-08-20  发布在  Java
关注(0)|答案(1)|浏览(360)

我有一个应用程序,有1个写入线程和8个读线程访问一个共享资源,它位于 ReentrantReadWriteLock . 它冻结了大约一个小时,没有产生日志输出,也没有响应请求。这是在Java8上实现的。
在杀死它之前,有人进行了线程转储,如下所示:
写入线程:

"writer-0" #83 prio=5 os_prio=0 tid=0x00007f899c166800 nid=0x2b1f waiting on condition [0x00007f898d3ba000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000002b8dd4ea8> (a java.util.concurrent.locks.ReentrantReadWriteLock$FairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
    at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:943)

读者:

"reader-1" #249 daemon prio=5 os_prio=0 tid=0x00007f895000c000 nid=0x33d6 waiting on condition [0x00007f898edcf000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000002b8dd4ea8> (a java.util.concurrent.locks.ReentrantReadWriteLock$FairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireShared(AbstractQueuedSynchronizer.java:967)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireShared(AbstractQueuedSynchronizer.java:1283)
    at java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.lock(ReentrantReadWriteLock.java:727)

这看起来像是一个僵局,但有两件事让我怀疑:
我找不到另一个线程可能持有相同的锁
4秒后进行线程转储会得到相同的结果,但现在所有线程都会报告 parking to wait for <0x00000002a7daa878> ,这与 0x00000002b8dd4ea8 在第一个垃圾场。
这是僵局吗?我看到线程的状态有一些变化,但它只能是锁实现的内部。还有什么可能导致这种行为?

velaa5lx

velaa5lx1#

这是僵局吗?
我不认为这是僵局的证据。至少,不是传统意义上的术语。
堆栈转储显示两个线程在同一时间等待 ReentrantReadWriteLock . 一个线程正在等待获取读锁。另一个正在等待获取写锁。
现在,如果当前没有线程持有任何锁,那么其中一个线程将能够继续。
如果其他线程当前持有写锁,则足以阻止这两个线程。但这并不是僵局。只有当第三个线程本身在等待另一个锁时,才会出现死锁。。。在阻塞中有一个圆形。
那么这两个线程相互阻塞的可能性呢?我认为那是不可能的。javadocs中的可重入性规则允许具有写锁的线程在不阻塞的情况下获取读锁。同样,如果它已经持有写锁,它也可以获得写锁。
另一个证据是,在稍后进行的线程转储中,情况发生了变化。如果出现真正的僵局,就不会有任何改变。
如果这不是(仅仅)这两个线程之间的死锁,那还会是什么呢?
一种可能性是第三个线程持有写锁(很长时间),这会把事情搞砸。这个读写锁上的争用太多了。
如果(假定)第三个线程正在使用 tryLock ,您可能有一个活锁。。。这可以解释“变化”证据。但另一方面,那根线也应该停下来。。。你说你看不见。
另一种可能是您有太多的活动线程。。。而操作系统正努力将它们安排到核心。
但这都是猜测。

相关问题