wait()过程
- 将当前线程包装成wait_node对象
- 将wait_node对象加入wait_set队列中
- 使用park()函数将该线程挂起同时释放锁
其他线程竞争锁过程(注意,这里的锁特指synchronize)
- 检查锁状态,如果为无锁状态则使用CAS竞争锁
- 如果为有锁状态,如果是锁的拥有者是该线程则返回
- 如果锁的拥有者不是该线程的则触发锁的膨胀机制
- 首先进入for死循环,查看锁的状态是否已经为重量级锁,如果是的话则直接返回
- 如果锁的状态时inflating(正在膨胀中)则等待一会
- 如果锁的状态是轻量级锁则使用CAS原语将其状态设置为inflating
- 设置成功的话objectMoniter对象的header,owner等字段都会更新并返回objectMoniter对象
- 膨胀成功后继续竞争锁
- 竞争失败的话将该线程包装成wait_node对象,并放入_cxq队列中
- 在_cxq队列中死循环再次竞争锁,如果竞争成功则打破循环,竞争失败则park()挂起线程
notify()过程
- 首先选择一个使用过wait()方法被放置到wait_set队列中的线程
- 根据策略的不同将该线程放入EntryList或者_cxq队列中
notify()方法并没有唤醒任何线程,因为当前线程可能并没有执行完任务,只是随机选择了一个线程并放置到了队列中
exit()过程
当线程执行完自己的任务后则会进入到此方法,这个方法才是释放锁唤醒其他线程的关键
- 释放锁
- 从EntryList或者_cxq队列中唤醒一个线程让其去竞争锁
为什么wait()/notify()必须在同步块内?
每个对象都拥有自己的monitor锁对象,当某一线程要使用wait()方法时他的前提是拥有锁对象,如果不在同步块内没拥有monitor对象的话那么就产生矛盾,同理notify()也是一样。其次比如在生产者-消费者模型中,如果不使用synchronize等同步方法话,当消费者发现产品数不够的时候准备wait()此时cpu资源不够转到生产者生产了一个产品,wait()方法在notify()方法之后执行,此时明明有产品但消费者使用了wait()不会再消费了。
简述yield(),sleep(),wait(),join()函数之间的区别
sleep()函数是使当前线程进入睡眠状态让出cpu资源,但该线程并不会释放自己的锁,只会让出cpu资源让其他不需要改锁对象的线程运行,sleep()函数需要设置睡眠时间。
yield()函数与sleep()函数类似,但是yield()函数没有输入参数,同让是让出cpu资源,但它只会让同等优先级的其他线程运行,他会首先查找与他同登优先级的线程,如果找到了便让出cpu资源。
join()函数是将cpu资源让给该方法的调用者然后当前线程进入睡眠状态。
(仅用于记录平时学习个人心得,如若有错恳请指教)