0

感谢您考虑我的问题,我认为这实际上是在问:

不太确定下面的代码到底是如何死锁的。


结构大致如下所示,有2 个类

  • 主类 -具有同步方法的Worker
  • 具有类级同步方法的util 类

Worker的run方法会死锁,doSomething()不同步可以避免死锁。


实际应用程序的线程转储显示:

“Worker”线程被阻塞-等待监视器锁定
-> int v = Utils.getIntValue();

“计划”线程正在等待 -此处的线程状态详细信息
--> 在 readWriteLock.readLock().lock() 之后的(ReentrantReadWriteLock 的内部代码);

at jdk.internal.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:885)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireShared(AbstractQueuedSynchronizer.java:1009)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireShared(AbstractQueuedSynchronizer.java:1324)
public class Worker {

    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public String getData() {

        try{
            readWriteLock.readLock().lock();
            return "Data";
        } finally {
            readWriteLock.readLock().unlock();
        }
    }

    public synchronized void doSomething() {
        // blocked due to the invocation of Utils.scheduleTask
        int v = Utils.getIntValue();
        System.out.println(v);
    }

    public void run() {
        // A static method which creates a thread that accesses the ReadWriteLock
        Utils.scheduleTask(this::getData);

        // some other quick tasks in between
        // ...

        // then enter this synchronized method
        doSomething();
    }
}
public class Utils {

    static synchronized void scheduleTask(Runnable task) {

        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1, r -> {
            Thread t = Executors.defaultThreadFactory().newThread(r);
            t.setName("schedule");
            return t;
        });

        executorService.schedule(task, 0L, TimeUnit.SECONDS);
    }

    static int getIntValue() {
        return 123;
    }
}

我认为这是由于静态同步方法scheduleTask锁定了整个Utils类,然后在线程ExecutorService可以获取内部 WorkerReadLock之前,另一种 Worker 方法锁定在 Worker 对象(内在锁)上,因此 2 个线程正在等待对方。ReentrantReadWriteLockdoSomething()


我可能完全错了,但如果到目前为止没有错,我不确定这个实例是如何ReentrantReadWriteLock知道引用它的 Worker 实例被另一个线程锁定的?

似乎当计划Runnable task运行时,即使scheduleTask方法返回,Utils 类仍然被锁定?



更新scheduleTask使用 0 秒延迟以更接近实际情况。


感谢您花时间考虑这个问题!

4

1 回答 1

0

事实证明,线程synchronized调用了另一种“Worker”方法,并且“Worker”的schedule超类中的方法被锁定在ReentrantReadWriteLock.WriteLock()...

“Worker”线程持有WriteLock并等待监视器锁

“schedule”线程持有 Worker 对象监视器锁并等待ReadLock

于 2021-06-04T15:35:47.617 回答