当涉及到多线程编程时,notify() 和 wait() 是Java中用于线程间通信的两个重要方法,它们通常与 synchronized 关键字一起使用。
wait()
wait()方法使当前线程进入等待状态,直到其他线程调用相同对象上的notify()或notifyAll()方法来唤醒该线程。wait()方法必须在同步块或同步方法中调用,以确保线程安全。- 当线程调用
wait()方法时,它会释放对象的锁,允许其他线程访问同步块或同步方法。 - 线程在等待状态中不会占用CPU时间,直到它被唤醒。
notify() 和 notifyAll()
notify()方法唤醒等待在相同对象上的一个线程,而notifyAll()方法则唤醒所有等待在相同对象上的线程。- 被唤醒的线程不会立即执行,而是需要等待调用
notify()或notifyAll()方法的线程释放锁之后才能继续执行。 - 通常情况下,应该使用
notifyAll()来确保所有等待线程都有机会被唤醒,以避免因为某些线程处于等待状态而导致死锁。
注意点
notify
This method should only be called by a thread that is the owner of this object's monitor. 只有持有该对象的monitor的线程才能调用
notify方法
wait
The current thread must own this object's monitor.
当前线程必须拥有此对象的monitor。
那么如何获取monitor?
- By executing a synchronized instance method of that object.
- By executing the body of a
synchronizedstatement that synchronizes on the object.- For objects of type
Class,by executing a synchronized static method of that class.
也就是加上 synchronized 对该对象添加monitor
如果没有加上synchronized 会怎么样呢?
java api doc
java 文档描述的是当前线程未持该monitor有会抛出IllegalMonitorStateException
Throws:
IllegalMonitorStateException- if the current thread is not the owner of this object's monitor.
下面是示例代码
public class Main {
public static void main(String[] str){
Object object = new Object();
object.notify();
}
}
最后会抛出异常
Exception in thread "main" java.lang.IllegalMonitorStateException: current thread is not owner
at java.base/java.lang.Object.notify(Native Method)
at com.demo.Main.main(Main.java:6)
monitor 归属检查的实现
ObjectMonitor::check_owner 被谁调用呢?
// -----------------------------------------------------------------------------
// Wait/Notify/NotifyAll
//
// Note: a subset of changes to ObjectMonitor::wait()
// will need to be replicated in complete_exit
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
JavaThread* current = THREAD;
assert(InitDone, "Unexpectedly not initialized");
CHECK_OWNER(); // 在这个宏里面被调用
}
CHECK_OWNER 宏展开之后就是调用ObjectMonitor::check_owner
#define CHECK_OWNER() \
do { \
if (!check_owner(THREAD)) { \
assert(HAS_PENDING_EXCEPTION, "expected a pending IMSE here."); \
return; \
} \
} while (false)
在ObjectMonitor::check_owner 会抛出异常current thread is not owner
// src/hotspot/share/runtime/objectMonitor.cpp
bool ObjectMonitor::check_owner(TRAPS) {
JavaThread* current = THREAD;
void* cur = owner_raw();
if (cur == current) {
return true;
}
if (current->is_lock_owned((address)cur)) {
set_owner_from_BasicLock(cur, current); // Convert from BasicLock* to Thread*.
_recursions = 0;
return true;
}
THROW_MSG_(vmSymbols::java_lang_IllegalMonitorStateException(),
"current thread is not owner", false); // 抛出异常信息current thread is not owner
}
最后我们看一下owner_raw()实现:
// src/hotspot/share/runtime/objectMonitor.inline.hpp
inline void* ObjectMonitor::owner_raw() const {
return Atomic::load(&_owner);
}
总结
wait和notify这个为什么要在synchronized代码块中?
- 因为api规定必须持有monitor
- 因为
wait和notify的语义就是为了线程之间协作和通信,为了保证资源的互斥性