无论如何如何在一段时间后释放Java ReentrantLock

问题描述 投票:0回答:2

我的目标是避免线程死锁或饥饿。我有以下使用 ReentranLocks 的示例代码:

 class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m1() { 
     lock.lock();  // block until condition holds
     try {
       // ... method body
       // ... start doing the calculations here ...
     } finally {
       //Do not release the lock here, instead, release it in m2()
     }
   }
   public void m2() { 
     try {
       // ... method body
       // ... continue doing the calculations here
     } finally {
       lock.unlock()
     }
   }

 }

我知道我可以使用

tryLock()
并设置超时,但我也在考虑确保无论如何都会解锁它,因为锁将在
m1()
中启动,并在
m2()
中解锁。如何确保我一启动锁,无论如何3秒后就能解锁
m1()

为了使上述成功,即。 3 秒后没有发送解锁请求,调用者或 JavaBean 的用户必须确保立即调用

m1()
,然后调用
m2()
。这是我想要避免的限制,如果程序员忘记这样做,可能会导致花费很长时间来解决这个问题,即
why the system is getting in a deadlock

想法:

我正在考虑使用计划任务和计时器,这可行吗?

java deadlock reentrantlock
2个回答
1
投票

只有持有锁的线程才可以释放锁。该线程可以跟踪它持有锁的时间,并在规定的时间间隔后释放它。或者,另一个线程可以等待规定的时间间隔,然后通知所有者线程停止其工作并释放锁。这可能是由于中断或其他情况造成的。

无论哪种情况,都需要编写持有锁的线程来支持超时机制,停止其工作,并释放锁。另一个线程不能强行撤销它的锁。


你可以做一些做作的事情来查看锁被持有的时间。这有不同的故障模式,无法解锁真正的锁;我觉得它更有可能造成损害,所以我个人不会使用它,但我不知道你的情况。 (我只是记录

lock()
并附上注释,以期望相应的
unlock()
日志以帮助故障排除,然后仔细检查我的代码。)

由于系统时间可能不连续且不单调,因此锁定的时间可能比指定时间多(多)或少。

这是一个(未经测试的)类,其作用就像一个只能持有指定时间的锁:

final class PseudoLock {

    private final Object lock = new Object();

    private final Clock clock;

    private final long limit;

    private final TimeUnit unit;

    private Instant acquired;

    PseudoLock(Clock clock, long limit, TimeUnit unit) {
        this.clock = Objects.requireNonNull(clock);
        if (limit < 1) throw new IllegalArgumentException();
        this.limit = limit;
        this.unit = Objects.requireNonNull(unit);
    }

    void acquire() throws InterruptedException {
        synchronized (lock) {
            Instant now = Instant.now(clock);
            while (acquired != null) {
                long delay = limit - acquired.until(now, unit.toChronoUnit());
                if (delay > 0) {
                    unit.timedWait(lock, delay);
                    now = Instant.now(clock);
                } else {
                    break;
                }
            }
            acquired = now;
        }
    }

    void release() {
        synchronized (lock) {
            acquired = null;
            lock.notify();
        }
    }

}

你可以像这样使用它:

class X {

   private final PseudoLock lock = 
     new PseudoLock(Clock.systemUTC(), 3L, TimeUnit.SECONDS);

   public void m1() { 
     lock.acquire();  // block until condition holds
     // ... method body
     // ... start doing the calculations here ...
   }

   public void m2() { 
     try {
       // ... method body
       // ... continue doing the calculations here
     } finally {
       lock.release();
     }
   }

}

0
投票

如何将

Semaphore
ScheduledExecutorService
一起使用?

在javadoc中

初始化为 1 的信号量,并且最多只有一个可用许可,可以用作互斥锁。这通常被称为二元信号量,因为它只有两种状态:一个可用许可,或零个可用许可。当以这种方式使用时,二进制信号量具有这样的属性(与许多 java.util.concurrent.locks.Lock 实现不同),即“锁”可以由除所有者之外的线程释放(因为信号量没有所有权的概念) )。这在某些特殊情况下很有用,例如死锁恢复。

唯一的限制是

Semaphore
不能重入。

或者你可以想一个方法来停止线程而不是释放锁

您可能会发现有用的额外来源: 解锁另一个线程java拥有的锁

© www.soinside.com 2019 - 2024. All rights reserved.