首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当使用ReentrantReadWriteLock时,这是死锁吗?

当使用ReentrantReadWriteLock时,这是死锁吗?
EN

Stack Overflow用户
提问于 2021-07-08 08:27:15
回答 2查看 1.1K关注 0票数 1

我有一个应用程序,它有一个写入线程和8个读取器线程访问共享资源,该资源位于ReentrantReadWriteLock后面。它冻结了大约一个小时,没有产生日志输出,也没有响应请求。这是在Java 8上。

在杀死它之前,有人使用线程转储,这些线程转储如下所示:

写作线索:

代码语言:javascript
复制
"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)

读者:

代码语言:javascript
复制
"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不同。

这是僵局吗?我看到线程的状态有一些变化,但它只能是锁实现的内部。还有什么原因会导致这种行为?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-07-22 13:27:18

原来是个僵局。持有锁的线程未被报告为在线程转储中持有任何锁,因此很难诊断。

了解这一点的唯一方法是检查应用程序的堆转储。对于那些对方法感兴趣的人来说,下面是一步一步的过程:

  1. 堆转储与线程转储的时间大致相同。
  2. 我使用Java VisualVM打开它,这是JDK附带的。
  3. 在“class”视图中,我按包含锁作为字段的类的类名进行了筛选。
  4. 我双击要被带到“实例”视图的类。
  5. 谢天谢地,这个类只有少数几个实例,所以我找到了造成问题的实例。
  6. 我检查了类中保存在字段中的ReentrantReadWriteLock对象。特别是,该锁的sync字段保持其状态--在本例中是ReentrantReadWriteLock$FairSync
  7. 它的state属性是65536。这表示了锁的共享和独占持有的数量。共享持有计数存储在状态的前16位中,并作为state >>> 16检索。独占保持计数在最后16位中,被检索为state & ((1 << 16) - 1)。从这一点我们可以看到,在锁上有一个共享的持有和零的独占持有。
  8. 您可以在head字段中看到等待锁的线程。它是一个队列,thread包含等待线程,next包含队列中的下一个节点。通过它,我找到了writer-0和8个reader-n线程中的7个,确认了我们从线程转储中知道的内容。
  9. 同步对象的firstReader字段包含从代码firstReader is the first thread to have acquired the read lock. 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.中的注释中获取读取日志的线程。

在这种情况下,持有锁的线程是reader线程之一。它是在完全不同的东西上被阻塞的,这需要其他reader线程中的一个进行。最终,它是由一个错误引起的,在这个错误中,读取器线程不能正确地释放锁,并且永远保持它。我是通过分析代码,并在获取和释放锁时添加跟踪和日志记录发现的。

票数 1
EN

Stack Overflow用户

发布于 2021-07-08 11:04:19

这是僵局吗?

我不认为这是僵局的证据。至少,不是这个词的经典意义上的。

堆栈转储显示两个线程在同一ReentrantReadWriteLock上等待。一个线程正在等待获取读锁。另一个正在等待获取写锁。

现在,如果当前没有线程持有任何锁,那么其中一个线程将能够继续执行。

如果其他线程当前持有写锁,则这足以阻塞这两个线程。但那不是僵局。只有当第三个线程本身在等待另一个锁时,这才是死锁.在阻塞中有一个循环。

那么这两个线程相互阻塞的可能性呢?我不认为那是可能的。javadocs中的重入规则允许具有写锁的线程在不阻塞的情况下获取读锁。同样,它可以获得它已经持有的写锁。

另一项证据是,在稍后的线程转储中,情况发生了变化。如果出现真正的僵局,就不会有任何变化。

如果这不是(仅仅)这两个线程之间的死锁,它还能是什么呢?

一种可能是第三个线程持有写锁(很长一段时间),这就把事情粘住了。关于这个readwrite锁的争论太多了。

如果(假定)第三个线程使用的是tryLock,则有可能有一个活锁.这可以解释“改变”的证据。但另一方面,那根线也应该停在.你说你看不见。

另一种可能是你有太多的活动线程。而操作系统正在努力将它们安排在核心上。

但这都是猜测。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68298055

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档