23

我有一个 LockManager 管理多个线程的锁。有时线程是坏孩子,我不得不杀死它们并要求 LockManager 释放它们所有的锁。但是,由于我在 java 中使用 ReentrantLock 这是不可能的,我无法解锁另一个线程拥有的锁。

我被迫使用锁(不能使用信号量,这是作业的重点)。是否有任何 Java Lock 实现允许我解锁其他线程拥有的锁?

到目前为止,我考虑的选项是:

  • 以允许我这样做的方式重新实现 ReentrantLock
  • 在信号量和可重入锁之间进行某种映射

您可能会发现有用的额外资源:

4

5 回答 5

12

你已经发现了一个普遍智慧说的主要原因:不要杀死线程!

如果你强行杀死一个线程,锁只是可能发生的潜在资源泄漏之一。考虑打开文件和套接字等。

还要考虑如果您确实设法解锁了锁,那么锁首先被锁定是有原因的。例如,线程可能已经部分更新了数据结构,并且允许从另一个线程访问该结构可能会导致奇怪而奇妙的程序故障,即使不是不可能调试也很难。

处理这种情况的最好方法是让线程离开。向与线程关联的对象添加一个“stop()”方法(每个线程都有一个对象,不是吗?),设置一个标志,并让线程定期检查这个标志,如果它被设置则退出.

如果您的线程的行为异常导致它们无法检查停止标志,那么正确的方法是修复代码以使其不会出现异常。

于 2013-05-10T21:58:58.853 回答
10

你会被允许使用你自己的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());
        }
    }
}
于 2013-05-10T23:41:39.070 回答
1

我已经使用 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");
        }
    }
}

''''

于 2019-05-02T22:12:54.280 回答
0

如评论中所述,杀死线程不是一个好习惯。大多数框架都会尽力中断工作队列中的线程,但只有在执行的代码通过调用Thread.isInterrupted()或调用可中断的 IO 或锁定方法检查中断标志时,它们才会生效。

如果您真的需要终止代码执行的概念,请查看Process该类。您可以Process通过调用Runtime.exec()或使用ProcessBuilder. 调用Process.destroyForcibly()会强制终止正在运行的进程。

于 2018-05-28T11:28:38.243 回答
-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

于 2013-05-10T21:59:38.127 回答