简体   繁体   English

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

[英]Why when using wait( ) , notify( ) , notifyAll( ) in java the thread using this part of code must be the only thread that own it's monitor?

The idea that when you remove the keyword synchronized when using wait( ), notify( ), notifyAll( ) it raises an error while running the program I know that wait( ), notify( ), notifyAll( ) must be included inside a synchronized block to make that thread using them the only thread owning the monitor on that pice of code but my question is: Why when using wait( ), notify( ), notifyAll( ) in java the thread using this part of code must be the only thread that own it's monitor?当您在使用 wait()、notify()、notifyAll() 时删除关键字 synchronized 的想法会在运行程序时引发错误我知道 wait()、notify()、notifyAll() 必须包含在 synchronized 中阻止使使用它们的线程成为那段代码上唯一拥有监视器的线程,但我的问题是:为什么在 java 中使用 wait()、notify()、notifyAll() 时,使用这部分代码的线程必须是唯一的拥有它的监视器的线程?

when remving the keyword synchronized from the pice of code that contains wait( ), notify( ) or notifyAll() this raises an error while I found no logical reason for that error当从包含 wait()、notify() 或 notifyAll() 的代码中移除关键字 synchronized 时,这会引发错误,而我没有发现该错误的逻辑原因

Requiring that the lock on the object is held resolves a race condition.要求持有 object 上的锁可以解决竞争条件。

Imagine that synchronized is not needed:想象一下不需要同步:

  • Thread A checks a flag and decides it needs to wait线程 A 检查标志并决定它需要等待
  • Thread B sets the flag线程 B 设置标志
  • Thread B calls notify线程 B 调用通知
  • Thread A actually calls wait线程A实际上调用了wait

Now Thread A will wait forever.现在线程 A 将永远等待。

With synchronized:与同步:

  • Thread A takes the lock线程A获取锁
  • Thread B wants to set the flag, so tries to take the lock, but is blocked线程 B 想要设置标志,因此尝试获取锁,但被阻塞
  • Thread A checks the flag线程 A 检查标志
  • Thread A calls wait (which releases the lock)线程 A 调用等待(释放锁)
  • Now thread B can set the flag and call notify现在线程 B 可以设置标志并调用通知
  • Thread A wakes up and sees the flag is set.线程 A 醒来并看到标志已设置。

When using synchronized , you're in fact locking an object.使用synchronized时,您实际上锁定了一个 object。

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

Only one thread at a time can lock onto that object. Unless you call wait() .一次只有一个线程可以锁定那个 object。除非你调用wait() If so, another thread is allowed for entering that critical section, doing it's stuff with that object and either calling wait() or notifying the other object holder(s) allowing them to continue past their wait() call.如果是这样,则允许另一个线程进入该关键部分,使用 object 执行此操作并调用wait()或通知其他 object 持有者,允许他们继续通过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");

Output: Output:

[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

Locking individual objects allows you for operating on more objects at a time.锁定单个对象允许您一次操作更多对象。

https://onecompiler.com/jshell/3ytda2qwz https://onecompiler.com/jshell/3ytda2qwz

In Java, the wait(), notify(), and notifyAll() methods can only be called from within a synchronized block or method.在 Java 中,只能从同步块或方法中调用 wait()、notify() 和 notifyAll() 方法。 When a thread calls one of these methods, it must be the owner of the monitor for the object on which the method is called.当线程调用这些方法之一时,它必须是调用该方法的 object 的监视器的所有者。

The reason for this is that these methods are used for inter-thread communication and synchronization, and they rely on the concept of monitors to ensure that only one thread can access a shared resource at a time.这样做的原因是这些方法用于线程间通信和同步,它们依赖于监视器的概念来确保同一时刻只有一个线程可以访问共享资源。 When a thread acquires the monitor for an object, it becomes the owner of the monitor and can use the wait(), notify(), and notifyAll() methods to communicate with other threads that may be waiting to acquire the monitor.当线程为 object 获取监视器时,它成为监视器的所有者,可以使用 wait()、notify() 和 notifyAll() 方法与可能正在等待获取监视器的其他线程进行通信。

If a thread tries to call one of these methods while it is not the owner of the monitor, it will throw an IllegalMonitorStateException.如果一个线程在它不是监视器所有者的情况下尝试调用这些方法之一,它将抛出 IllegalMonitorStateException。

Here is an example of how you could use the wait(), notify(), and notifyAll() methods in a synchronized block:以下是如何在同步块中使用 wait()、notify() 和 notifyAll() 方法的示例:

synchronized (myObject) {
  // The current thread is now the owner of the monitor for myObject
  myObject.wait();
  // The current thread is now waiting for a notification from another thread
  // ...
  myObject.notify();
  // The current thread has notified one other waiting thread
  myObject.notifyAll();
  // The current thread has notified all waiting threads
}

I hope this helps!我希望这有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM