两个线程如何进入两个同步块,这些块在同一个对象上保持锁定

tra*_*t0r 0 java multithreading synchronized

我有一些像这样的代码:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

ThreadB类:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

1
Waiting for b to complete... 
22
Waiting for b to complete...
Run Code Online (Sandbox Code Playgroud)

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

怎么可能?

此外,如果我在threadB.run()方法中插入2个其他行:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

2个线程运行完成:

Total is: 4950
22
1
Waiting for b to complete...
Waiting for b to complete...
Total is: 4950
Total is: 4950
Run Code Online (Sandbox Code Playgroud)

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

此外,如果一个线程退出而没有调用notify(),则内部释放锁(相当于notifyAll()).是对的吗?

Sea*_*ght 5

因为调用Object.wait()会释放锁定.从文档:

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

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

  2. 此外,如果一个线程退出而没有调用notify(),则内部释放锁(相当于notifyAll()).是对的吗?一旦线程进入wait(),锁定就已经释放.

  • 我向你倾倒了,amitmah.你根本没有说同样的事情:你没有说'wait()`释放锁; 你没有链接到文档.你只是做了一个模糊的陈述:"在你的输出中,当线程1持有锁定时,你得到第一行打印,必须在第二行输出锁定被第二个线程获取." (它只是描述了问题中展示的行为而没有解释它),然后说你不确定.对不起,这不是一个有用的答案. (2认同)
  • @ trans1st0r:"因此,通知告知等待线程你可能获得释放的锁,对吗?" 不,通知告诉等待的线程被唤醒,但是没有给该线程任何获得锁定的特殊权限.与可能争用锁的其他线程相比,通知的线程没有任何特殊优势. (2认同)