当一个线程结束时,它会释放锁吗?

12

我在某些地方读到过,获取一个Lock对象时最好将其包含在try...finally块中,这样即使抛出异常也可以释放锁。

可能听起来很简单的问题:所有属于线程的锁在线程完成时自动释放吗?

我问这个问题的原因是,我正在处理的程序是这样的,一旦线程获取锁,它就没有理由在完成之前释放它。此外,我刚开始使用锁,所以想知道是否有任何我尚未考虑到的陷阱。我是否需要在线程完成之前在代码中显式释放锁,还是可以将其留给JVM,在确定其他线程被阻塞在所有活动线程的锁上并且在活动线程停止后立即激活?


请发布一些代码。 - IamK
@C1sc0:关于什么的一些代码?问题陈述非常清晰。 - Patrick
您可以尝试使用非常简单的应用程序对此进行测试。创建两个线程,尝试获取相同的锁定并直接终止线程。如果第二个线程获得了锁,则确实已解锁。 - Patrick
2
这取决于锁的实现方式,但一般来说不会。 - ZhongYu
@Patrick 我知道我有点懒...这是我的方式...我想我可以继续假设锁会自动释放,看看我的程序如何应对... - user1941660
1个回答

9

简单的测试可能会显示出线程终止后锁没有释放:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {
    public static void main(String[] args) {
        final Lock l = new ReentrantLock();

        Thread t = new Thread() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread()+": Acquire lock");
                l.lock();
                System.out.println(Thread.currentThread()+": Lock aquired: wait");
                LockSupport.parkNanos(1_000_000_000);
                System.out.println(Thread.currentThread()+"; Exiting");
            }
        };
        t.start();
        LockSupport.parkNanos(500_000_000);
        System.out.println(Thread.currentThread()+": Acquire lock");
        l.lock();
        System.out.println(Thread.currentThread()+"; Success!");
    }
}

输出:

Thread[Thread-0,5,main]: Acquire lock
Thread[Thread-0,5,main]: Lock aquired: wait
Thread[main,5,main]: Acquire lock
Thread[Thread-0,5,main]; Exiting
// "Success" is never written: stuck in dead-lock

因此,当单独的线程获得锁并退出时,主线程无法获取锁。


将已被特定线程获取的锁与该线程关联起来会很好 - API(令人惊讶地)似乎没有做到这一点。我想可以在自定义线程实现中保存已获取的锁的集合,并在线程即将完成之前释放它们。我不知道这是否存在风险... - user1941660
1
@OwenThomas,API确实将锁与线程关联起来。您可以尝试在另一个线程中解锁已获取的锁:这将导致异常。在线程完成后添加自动解锁太过于繁琐和不必要。 - Tagir Valeev
有没有一种方法可以在当前线程上调用 - 类似于getLocks() - 返回包含该线程锁的集合? - user1941660
1
@OwenThomas,你可以使用类似于ManagementFactory.getThreadMXBean().getThreadInfo(..).getLockedMonitors(..)的方法来实现此操作,但是你将无法获得Lock对象本身,而是线程使用的原始监视器。 - Tagir Valeev
嗯...看起来有点笨重...你认为在Thread的子类(或者实现Runnable或Callable接口的类)中包含这样一个集合会不会行得通? - user1941660
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接