一个持有多个锁的线程进入等待状态,它会释放所有持有的锁吗?

7

我编写了这个程序,以检查线程t1是否持有锁定两个不同对象:Lock.class和MyThread.class,并使用MyThread.class.wait()将其置于MyThread.class实例的等待模式中。它不会释放对Lock.class实例的锁定。为什么?我一直认为,一旦线程进入等待模式或死亡,它就会释放所有已获得的锁。

public class Lock {

protected static volatile boolean STOP = true;
public static void main(String[] args) throws InterruptedException {
    MyThread myThread = new MyThread();
    Thread t1 = new Thread(myThread);
    t1.start();
    while(STOP){
    }
    System.out.println("After while loop");
    /*
     * 
     */
    Thread.sleep(1000*60*2);
    /*
     * Main thread should be Blocked.
     */
    System.out.println("now calling Check()-> perhaps i would be blocked. t1 is holding lock on class instance.");
    check();
}

public static synchronized void check(){
    System.out.println("inside Lock.check()");
    String threadName = Thread.currentThread().getName();
    System.out.println("inside Lock.Check() method : CurrrentThreadName : "+ threadName);
}
}


class MyThread implements Runnable{
public MyThread() {
}

@Override
public void run() {
    try {
        System.out.println("inside Mythread's run()");
        classLocking();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public static synchronized void classLocking() throws InterruptedException{
    System.out.println("inside Mythread.classLocking()");
    String threadName = Thread.currentThread().getName();
    System.out.println("inside MyThread.classLocking() : CurrrentThreadName : "+ threadName);
    /*
     * outer class locking 
     */
    synchronized (Lock.class) {
        System.out.println("I got lock on Lock.class definition");
        Lock.STOP = false;
        /*
         * Outer class lock is not released. Lock on MyThread.class instance is released.
         */
        MyThread.class.wait();
    }
}
}
4个回答

5
您是正确的,它并不释放其他锁。为什么呢?这是因为这样做是不安全的。如果在调用内部函数时释放外部锁是安全的,那么为什么在调用内部函数时还需要持有其他锁呢?
让一个函数在程序员不知情的情况下释放它没有获取的锁会破坏同步函数的逻辑。

谢谢回复。一旦t1进入等待模式并不再活动,为什么它会持有Lock.class实例的锁定? - HakunaMatata
一个函数确实可以轻松释放它没有获取的锁:synchronized void a() { b(); } void b() { wait(); } -- 是 b 释放了由 a 获取的锁。 - Marko Topolnik
@MarkoTopolnik:是的,但这只是因为ab是同一接口的一部分,因此必须作为一个单元进行设计。 - David Schwartz
@ManishBhunwal:为了防止其他线程访问它。如果其他线程可以安全地访问对象,那么为什么它一直持有锁呢? - David Schwartz
1
我想我已经澄清了。谢谢。 - David Schwartz
显示剩余4条评论

0

wait() 的语义是,调用它的线程注意到另一个线程已经获取了锁,被挂起并等待持有锁的线程释放它(并调用 notify)。这并不意味着在等待时它会释放所有已获取的锁。您可以将 wait 的调用视为线程在获取完成操作所需的所有锁之前遇到的一些障碍。

关于问题“为什么线程在调用 wait 时不释放所有已获取的锁”,我认为答案是这样做会使其更容易饱和,并且会减慢多线程应用程序的进度(当所有线程在调用第一个 wait 时都会放弃所有锁,并且在它们获取当前正在等待的锁时必须重新开始。因此,它们将永久争夺锁。 实际上,在这样的系统中,唯一能够完成执行的线程是在需要它们时找到所有空闲锁的线程。这种情况不太可能发生)


0

来自wait()方法的JavaDoc

当前线程必须拥有此对象的监视器。线程释放对此监视器的所有权,并等待另一个线程通过调用notify方法或notifyAll方法通知等待在此对象监视器上的线程唤醒。然后,该线程等待,直到它可以重新获得监视器的所有权并恢复执行。


0

是的,它正常工作。线程进入等待状态时会释放相应的锁,而不是所有锁。否则请考虑一下:如果事情像你想的那样,那么当线程等待时,它将失去所有已获得的锁,这使得高级顺序执行变得不可能。


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