我有一个LockManager来管理多个线程的锁。有时线程是坏男孩,我必须杀死它们并要求LockManager释放所有锁。但是,由于我在java中使用ReentrantLock这是不可能的,我无法解锁另一个线程所拥有的锁。
我被迫使用Locks(不能使用信号量,这是功课的重点)。是否有任何Java Lock实现允许我解锁其他线程拥有的锁?
到目前为止,我考虑的选项是:
您可能会发现有用的额外资源:
答案 0 :(得分:11)
你已经发现了一个普遍智慧的主要原因:不要杀死线程!
锁只是强行杀死线程时可能发生的潜在资源泄漏之一。考虑打开文件和套接字等。
另外考虑一下,如果您确实设法解锁了锁,那么首先锁定锁是有原因的。例如,线程可能已部分更新数据结构,并允许从另一个线程访问该结构可能会导致奇怪和奇妙的程序故障,即使不是不可能调试也很困难。
处理这种情况的最好方法是让线程消失。添加一个“stop()”方法到与线程关联的对象(你有一个每个线程的对象,不是吗?)设置一个标志,让线程定期检查这个标志,如果设置了则退出
如果您的线程行为不当,导致他们无法检查停止标志,那么正确的方法是修复代码,使其不会出现异常行为。
答案 1 :(得分:7)
您是否可以使用自己的Lock
?这是一个完全代理Lock
的类,但是当它被告知强制解锁时,它只是替换了它用新代理代替的锁。这应该具有你想要的效果。可悲的是,它仍然没有处理悬挂的锁,但现在成为别人的问题。你的锁现在神奇地解锁了。
static class LockProxy<L extends Lock> implements Lock {
// The actual lock.
private volatile Lock lock;
public LockProxy(L lock) {
// Trap the lock we are proxying.
this.lock = lock;
}
@Override
public void lock() {
// Proxy it.
lock.lock();
}
@Override
public void lockInterruptibly() throws InterruptedException {
// Proxy it.
lock.lockInterruptibly();
}
@Override
public boolean tryLock() {
// Proxy it.
return lock.tryLock();
}
@Override
public boolean tryLock(long l, TimeUnit tu) throws InterruptedException {
// Proxy it.
return lock.tryLock(l, tu);
}
@Override
public void unlock() {
// Proxy it.
lock.unlock();
}
@Override
public Condition newCondition() {
// Proxy it.
return lock.newCondition();
}
// Extra functionality to unlock from any thread.
public void forceUnlock() {
// Actually just replace the perhaps locked lock with a new one.
// Kinda like a clone. I expect a neater way is around somewhere.
if (lock instanceof ReentrantLock) {
lock = new ReentrantLock();
} else {
throw new UnsupportedOperationException(
"Cannot force unlock of lock type "
+ lock.getClass().getSimpleName());
}
}
}
答案 2 :(得分:0)
正如评论中所述,杀死线程不是一个好习惯。大多数框架都尽力中断工作队列中的线程,但只有执行的代码通过调用Thread.isInterrupted()
或调用可中断的IO或锁定方法来检查中断标志时,它们才会生效。
如果您真的需要杀死代码执行的概念,请查看Process
类。您可以致电Process
或使用Runtime.exec()
来创建ProcessBuilder
。调用Process.destroyForcibly()
将强行终止正在运行的进程。
答案 3 :(得分:0)
我已经用AtomicReference做到了这一点,优雅度得到了零分,但我不知道另一种方法。
class PseudoLock {
private final AtomicReference<Boolean> mylock = new AtomicReference<>(Boolean.FALSE);
boolean trylock() {
return mylock.compareAndSet(Boolean.FALSE, Boolean.TRUE);
}
void unlock() {
boolean done = mylock.compareAndSet(Boolean.TRUE, Boolean.FALSE);
if (!done) {
throw new IllegalStateException("Cannot unlock an unlocked thread");
}
}
}
''''
答案 4 :(得分:-2)
为什么不简单地将线程代码包装在以下内容中:
ReentrantLock lock = ... obtain your lock somehow ...
lock.lock();
try {
... the "bad boy" code here ...
} finally {
lock.unlock();
}
然后,当你的线程完成时(通过正常完成,或通过从你的“kill”中抛出异常),它将释放锁。
这实际上是Oracle推荐使用ReentrantLock的方式:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html