Unlocking lock owned by another thread java

久未见 提交于 2019-12-30 01:54:27

问题


I have a LockManager that manages the locks of several threads. Sometimes the threads are bad boys, and I have to kill them and ask the LockManager to release all their locks. However, since I use ReentrantLock in java this is impossible, I can not unlock a lock owned by another thread.

I am forced to use Locks (cannot use semaphores, it is point of the homework). Is there any Java Lock implementation that allows me to unlock locks owned by other threads?

So far the options I considered are:

  • re-implementing ReentrantLock in a way that allows me to do this
  • Make some sort of mapping between Semaphores and ReentrantLocks

Extra Sources you may find useful:

  • Reentrant locks - Unlocking from another thread
  • Unlocking a lock from a thread which doesn't own it, or redesigning to avoid this?

回答1:


Would you be allowed to use your own Lock? Here's a class that completely proxies the Lock but when it is told to force the unlock it merely replaces the lock it is proxying with a new one. This should have the effect you want. Sadly it still does not deal with the locks that are left dangling but that now becomes somebody else's problem. Your locks are now magically unlocked.

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:


You've discovered a major reason why common wisdom says: Don't kill threads!

Locks are only one of the potential resource leaks that can happen if you forcibly kill a thread. Consider open files and sockets, etc.

Also consider that if you did manage to unlock the lock, there was a reason the lock was locked in the first place. For example, the thread may have partially updated a data structure, and allowing access to that structure from another thread is likely to cause strange and wondrous program failures that are difficult if not impossible to debug.

The best way to handle this situation is to ask the thread to go away. Add a "stop()" method to the object associated with the thread (you do have an object for each thread, don't you?) that sets a flag, and have the thread check this flag regularly and exit if it is set.

If your threads are misbehaving in a way that prevents them from checking the stop flag, then the correct approach is to fix the code so that it does not misbehave.




回答3:


As stated in the comments, killing threads is not a good practice. Most frameworks do their best to interrupt threads in worker queues, but they will only have an effect if the executed code checks the interrupt flag, either by calling Thread.isInterrupted() or calling an interruptable IO or lock method.

If you really need the concept of killing the execution of code, have a look at the Process class. You can create a Process by calling Runtime.exec() or using the ProcessBuilder. Calling Process.destroyForcibly() will forcibly terminate the running process.




回答4:


I've done this with an AtomicReference which gets zero points for elegance, but I don't know of another way.

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");
        }
    }
}

''''




回答5:


Why don't you simply wrap the code of your thread around the following:

ReentrantLock lock = ... obtain your lock somehow ...
lock.lock();
try {
  ... the "bad boy" code here ...
} finally {
  lock.unlock();
}

Then, when your thread finishes (either by normally finishing, or by throwing an exception from your "kill"), it will release the lock.

This is actually the way Oracle recommends using ReentrantLock: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html



来源:https://stackoverflow.com/questions/16491287/unlocking-lock-owned-by-another-thread-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!