web-dev-qa-db-ja.com

別のスレッドが所有するロックのロックを解除するjava

複数のスレッドのロックを管理するLockManagerがあります。時々スレッドは悪い子です、そして私はそれらを殺して、LockManagerにそれらのすべてのロックを解放するように頼まなければなりません。ただし、JavaでReentrantLockを使用しているため、これは不可能であるため、別のスレッドが所有するロックのロックを解除できません。

ロックを使用せざるを得ません(セマフォは使用できません。宿題のポイントです)。他のスレッドが所有するロックのロックを解除できるJavaロックの実装はありますか?

これまでのところ、私が検討したオプションは次のとおりです。

  • これを可能にする方法でReentrantLockを再実装する
  • セマフォとReentrantLocksの間にある種のマッピングを作成します

あなたが役に立つと思うかもしれない追加の情報源:

19
Flame_Phoenix

独自の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());
        }
    }
}
7
OldCurmudgeon

あなたは一般的な知恵が言う主な理由を発見しました:スレッドを殺さないでください!

ロックは、スレッドを強制的に強制終了した場合に発生する可能性のある潜在的なリソースリークの1つにすぎません。開いているファイルやソケットなどを検討してください。

また、ロックを解除できた場合は、そもそもロックがロックされていた理由があることも考慮してください。たとえば、スレッドがデータ構造を部分的に更新した可能性があり、別のスレッドからその構造へのアクセスを許可すると、デバッグが不可能ではないにしても困難な、奇妙で不思議なプログラム障害が発生する可能性があります。

この状況に対処する最善の方法は、スレッドに立ち去るように依頼することです。フラグを設定するスレッドに関連付けられたオブジェクトに「stop()」メソッドを追加し(スレッドごとにオブジェクトがありますね)、スレッドにこのフラグを定期的にチェックさせ、設定されている場合は終了します。 。

スレッドが停止フラグをチェックできないように誤動作している場合、正しいアプローチは、誤動作しないようにコードを修正することです。

11
Dale Wilson

エレガンスでゼロポイントを取得する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");
        }
    }
}

'' ''

1
Kurt

コメントで述べられているように、スレッドを強制終了することは良い習慣ではありません。ほとんどのフレームワークは、ワーカーキュー内のスレッドに割り込むために最善を尽くしますが、実行されたコードがThread.isInterrupted()を呼び出すか、割り込み可能なIOを呼び出すことによって、割り込みフラグをチェックする場合にのみ効果があります。ロック方式。

コードの実行を強制終了するという概念が本当に必要な場合は、Processクラスを参照してください。 Runtime.exec()を呼び出すか、Processを使用して、ProcessBuilderを作成できます。 Process.destroyForcibly()を呼び出すと、実行中のプロセスが強制的に終了します。

0
benez