为什么在java中使用wait()、notify()、notifyAll()时,使用这部分代码的线程必须是唯一拥有其监视器的线程?

crcmnpdw  于 2023-01-01  发布在  Java
关注(0)|答案(2)|浏览(107)

在使用wait()、notify()、notifyAll()时删除关键字synchronized会在运行程序时引发错误,我知道wait()、notify()、notifyAll()必须包含在synchronized块中,以使使用它们的线程成为唯一拥有该代码块上的监视器的线程,但我的问题是:为什么在java中使用wait()、notify()、notifyAll()时,使用这部分代码的线程必须是唯一拥有其监视器的线程?
从包含wait()、notify()或notifyAll()的代码块中删除synchronized关键字时,会引发错误,但我找不到该错误的逻辑原因

erhoui1w

erhoui1w1#

要求持有对象上的锁解决了争用条件。
假设不需要同步:

  • 线程A检查一个标志并决定它需要等待
  • 线程B设置标志
  • 线程B调用通知
  • 线程A实际调用wait

现在线程A将永远等待。
使用同步:

  • 线程A获取锁
  • 线程B希望设置该标志,因此尝试获取锁,但被阻塞
  • 线程A检查标志
  • 线程A调用wait(释放锁)
  • 现在线程B可以设置标志并调用notify
  • 线程A醒来并看到标志被设置。
2exbekwf

2exbekwf2#

使用synchronized时,实际上是在锁定一个对象。

final Object lock = new Object();
// ...
synchronized (lock) {
    // ...
}

一次只有一个线程可以锁定该对象。除非你调用wait()。如果是这样,另一个线程被允许进入该临界区,对该对象做它自己的事情,或者调用wait(),或者通知其他对象保持器,允许他们继续进行wait()调用。

void log(String message) {
    System.out.println("[" + Thread.currentThread().getName() + "] " + message);
}

final int max = 10;
final Object valueLock = new Object();
volatile int value = 0;

Thread setupThread = new Thread(() -> {
    log("Started");
    for (int i = 0; i < max; i++) {
        Thread valueThread = new Thread(() -> {
            log("Started");
            try {
                Thread.sleep(new Random().nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized(valueLock) {
                log(value + " -> " + (++value));
                valueLock.notifyAll();
            }
            log("Finished");
        });
        valueThread.start();
    }
    log("Finished");
}, "setupThread");

setupThread.start();

log("Waiting for the value to reach " + max);
synchronized(valueLock) {
    while (true) {
        if (value < max) {
            valueLock.wait();
        } else {
            break;
        }
    }
}
log("Finished");

输出:

[setupThread] Started
[Thread-0] Started
[Thread-1] Started
[Thread-2] Started
[Thread-3] Started
[Thread-4] Started
[Thread-5] Started
[Thread-6] Started
[Thread-7] Started
[Thread-8] Started
[setupThread] Finished
[Thread-9] Started
[Thread-2] 0 -> 1
[Thread-2] Finished
[Thread-6] 1 -> 2
[Thread-6] Finished
[Thread-4] 2 -> 3
[Thread-4] Finished
[Thread-5] 3 -> 4
[Thread-5] Finished
[Thread-1] 4 -> 5
[Thread-1] Finished
[Thread-0] 5 -> 6
[Thread-0] Finished
[main] Waiting for the value to reach 10
[Thread-7] 6 -> 7
[Thread-7] Finished
[Thread-8] 7 -> 8
[Thread-8] Finished
[Thread-3] 8 -> 9
[Thread-3] Finished
[Thread-9] 9 -> 10
[Thread-9] Finished
[main] Finished

锁定单个对象允许您一次操作多个对象。
https://onecompiler.com/jshell/3ytda2qwz

相关问题