当前位置: 首页 > 面试题库 >

什么是线程转储中的“锁定的可拥有同步器”?

陈法
2023-03-14
问题内容

我试图了解Locked ownable synchronizers线程转储中指的是什么?

我开始使用ReentrantReadWriteLock一个处于WAITING状态的线程,等待ReentrantReadWriteLock$FairSync另一个处于WAITING状态(a
ThreadPoolExecutor)的线程的“锁定的拥有者同步器”列表中。

我找不到太多有关此的信息。它是某种“传递到”线程的锁吗?我试图找出死锁的来源,并且看不到任何线程正在主动锁定死锁(即- 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那样容易”)。

编辑:为了帮助弄清楚复制/粘贴错误,并带有未释放的锁,例如:

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)的详细信息。



 类似资料:
  • 问题内容: 我有一个LockManager来管理多个线程的锁。有时线程是坏男孩,我必须杀死它们并要求LockManager释放所有锁。但是,由于我无法在Java中使用ReentrantLock,因此无法解锁另一个线程拥有的锁。 我被迫使用锁(不能使用信号灯,这是作业的重点)。是否有任何Java Lock实现可让我解锁其他线程拥有的锁? 到目前为止,我考虑的选项是: 以允许我执行此操作的方式重新实现

  • 我有一个LockManager管理几个线程的锁。有时线程是坏男孩,我必须杀死他们,并要求锁经理释放他们所有的锁。但是,由于我在java中使用ReentrantLock,这是不可能的,我不能解锁另一个线程拥有的锁。 我被迫使用锁(不能使用信号量,这是作业的重点)。是否有Java锁实现允许我解锁其他线程拥有的锁? 到目前为止,我考虑的选择是: null 可重入锁-从另一个线程解锁 从不拥有锁的线程中解

  • 问题内容: 我想知道什么是Java线程转储。有人可以帮我了解什么是线程转储以及它与正在运行的Java程序的关系吗? 问题答案: Java线程转储是一种找出JVM中每个线程在特定时间点正在做什么的方法。如果您的Java应用程序有时在负载下运行时挂起,这将特别有用,因为对转储的分析将显示线程卡在哪里。 您可以通过运行并通过单击生成线程转储。 要了解如何从JVM进行线程转储,请参见此处 要了解如何创建线

  • 问题内容: 我写了一个简单的代码来模拟使用and的并发。 源代码如下: 任务类 包括一个用于打印线程名称和执行经过时间的方法。 TaskWithLock 类 TaskWithSync 类 主 班 第一次,通过调用方法 runableTasks(TaskWithSync.class); 执行带有Synchronized的任务 ; 第二次,通过调用 runableTasks(TaskWithLock.

  • 类型 pthread_mutex_t 互斥锁基本操作 函数 描述 [[pthread_mutex_init pthread_mutex_init]] 初始化互斥锁 [[pthread_mutex_lock pthread_mutex_lock]] 阻塞申请互斥锁 [[pthread_mutex_unlock pthread_mutex_unlock]] 释放互斥锁 [[pthread_mutex_

  • 问题内容: 基本上,我看到了一个BLOCKED线程,但它具有等待的锁: 我希望能看到而不是。另一个问题表明垃圾回收是原因,但是如果是这种情况,不是所有线程都被阻塞了吗?还有其他线程是可运行的。另外,我怎么能证明是这种情况?为什么这是观察到的行为?我不想盲目假设它是垃圾收集器,只是几天后才发现它是其他东西。 ==辅助信息== 尽管我认为这与手头的问题无关,但这是上述转储来自的代码部分。 显然,在那条