1. wait,notify都是锁对象来调用的,一个锁对象会维护两个队列,一个是等待队列(存放调用wait方法的线程),一个是就绪队列(等待获取锁的线程的对象),等待队列的线程是无法参与锁竞争的,只有调用notify/notifyall 后可以把等待队列的线程移到就绪队列中,然后才能参加锁竞争。
openjdk c++源码分析:
路径:openjdk\hotspot\src\share\vm\runtime\objectMonitor.hpp
ObjectMonitor() {
_header = NULL;
_count = 0;
_waiters = 0,
_recursions = 0;
_object = NULL;
_owner = NULL;
_WaitSet = NULL; // 等待队列
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ; // 就绪队列
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
_previous_owner_tid = 0;
}
2.线程被唤醒的情况:
- 被其他线程调用notify、notifyAll方法唤醒;
- 如果是超时等待,那么时间到来了,线程也会自动唤醒。
- 有中断发生,线程的等待状态被打断,强制唤醒。(interrupt())
notifyAll是怎么实现全唤起所有线程
或许大家立马想到这个简单,一个for循环就搞定了,不过在JVM里没实现这么简单,而是借助了monitorexit,上面提到了当某个线程从wait状态恢复出来的时候,要先获取锁,然后再退出同步块,所以notifyAll的实现是调用notify的线程在退出其同步块的时候唤醒起最后一个进入wait状态的线程,然后这个线程退出同步块的时候继续唤醒其倒数第二个进入wait状态的线程,依次类推,同样这这是一个策略的问题,JVM里提供了挨个直接唤醒线程的参数。