两个线程如何进入两个对同一个对象持有锁的同步块

How can two threads enter two synchronized blocks which hold a lock on the same object

我有一些这样的代码:

public class HelloWorld {
    public static void main(String[] args){
        ThreadB b = new ThreadB();
        b.start();

        Runnable a = new Runnable(){
            public void run(){
                System.out.println(Thread.currentThread().getId());
                synchronized(b){
                    try{
                        System.out.println("Waiting for b to complete...");
                        b.wait();
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                    System.out.println("Total is: " + b.total);
                }
            }
        };

        (new Thread(a)).start();

        synchronized(b){
            System.out.println(Thread.currentThread().getId());
            try{
                System.out.println("Waiting for b to complete...");
                b.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }

            System.out.println("Total is: " + b.total);
        }
    }
}

Class 线程 B:

class ThreadB extends Thread{
    int total;
    @Override
    public void run(){
        synchronized(this){
            for(int i=0; i<100 ; i++){
                total += i;
            }
            System.out.println("Total is: " + total);
            notify();
        }
    }
}

基本上,我有两个锁定 Threadb 对象 b 的线程。当我 运行 代码时,我看到:

1
Waiting for b to complete... 
22
Waiting for b to complete...

这里,数字是线程id,很明显,它们是不同的线程。 此外,他们锁定的对象是相同的(b)。但是,两者都能够进入同步块并等待对象。

怎么可能?

此外,如果我在 threadB.run() 方法中插入另外两行:

class ThreadB extends Thread{
    int total;
    @Override
    public void run(){
        synchronized(this){
            for(int i=0; i<100 ; i++){
                total += i;
            }
            System.out.println("Total is: " + total);
            notify();
        }
    }
}

2个线程运行完成:

Total is: 4950
22
1
Waiting for b to complete...
Waiting for b to complete...
Total is: 4950
Total is: 4950

似乎在 ThreadB.run() 的旧定义中,等待线程错过了通知信号,因此它们无限期地等待。正确吗?

另外,如果一个线程在没有调用 notify() 的情况下退出,锁将在本质上被释放(等同于 notifyAll())。是吗?

因为调用Object.wait()释放了锁。来自 the documentation:

The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

  1. 似乎在 ThreadB.run() 的旧定义中,等待线程错过了通知信号,因此它们无限期地等待.它是正确的吗? 他们 wait() 直到他们被 notify() 了(这可能是虚假的)或者他们被打断了。

  2. 此外,如果线程在未调用 notify() 的情况下退出,则锁会在本质上释放(相当于 notifyAll())。是这样吗?一旦线程wait()ing,锁就已经释放了。