我的目标是避免线程死锁或饥饿。我有以下使用 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
。
我正在考虑使用计划任务和计时器,这可行吗?
只有持有锁的线程才可以释放锁。该线程可以跟踪它持有锁的时间,并在规定的时间间隔后释放它。或者,另一个线程可以等待规定的时间间隔,然后通知所有者线程停止其工作并释放锁。这可能是由于中断或其他情况造成的。
无论哪种情况,都需要编写持有锁的线程来支持超时机制,停止其工作,并释放锁。另一个线程不能强行撤销它的锁。
你可以做一些做作的事情来查看锁被持有的时间。这有不同的故障模式,无法解锁真正的锁;我觉得它更有可能造成损害,所以我个人不会使用它,但我不知道你的情况。 (我只是记录
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();
}
}
}
如何将
Semaphore
与ScheduledExecutorService
一起使用?
在javadoc中
初始化为 1 的信号量,并且最多只有一个可用许可,可以用作互斥锁。这通常被称为二元信号量,因为它只有两种状态:一个可用许可,或零个可用许可。当以这种方式使用时,二进制信号量具有这样的属性(与许多 java.util.concurrent.locks.Lock 实现不同),即“锁”可以由除所有者之外的线程释放(因为信号量没有所有权的概念) )。这在某些特殊情况下很有用,例如死锁恢复。
唯一的限制是
Semaphore
不能重入。
或者你可以想一个方法来停止线程而不是释放锁
您可能会发现有用的额外来源: 解锁另一个线程java拥有的锁