Object中wait()/notify()机制

383 阅读3分钟
wait()过程
  1. 将当前线程包装成wait_node对象
  2. 将wait_node对象加入wait_set队列中
  3. 使用park()函数将该线程挂起同时释放锁
其他线程竞争锁过程(注意,这里的锁特指synchronize)
  1. 检查锁状态,如果为无锁状态则使用CAS竞争锁
  2. 如果为有锁状态,如果是锁的拥有者是该线程则返回
  3. 如果锁的拥有者不是该线程的则触发锁的膨胀机制
    • 首先进入for死循环,查看锁的状态是否已经为重量级锁,如果是的话则直接返回
    • 如果锁的状态时inflating(正在膨胀中)则等待一会
    • 如果锁的状态是轻量级锁则使用CAS原语将其状态设置为inflating
    • 设置成功的话objectMoniter对象的header,owner等字段都会更新并返回objectMoniter对象
  4. 膨胀成功后继续竞争锁
  5. 竞争失败的话将该线程包装成wait_node对象,并放入_cxq队列中
  6. _cxq队列中死循环再次竞争锁,如果竞争成功则打破循环,竞争失败则park()挂起线程
notify()过程
  1. 首先选择一个使用过wait()方法被放置到wait_set队列中的线程
  2. 根据策略的不同将该线程放入EntryList或者_cxq队列中 notify()方法并没有唤醒任何线程,因为当前线程可能并没有执行完任务,只是随机选择了一个线程并放置到了队列中
exit()过程

当线程执行完自己的任务后则会进入到此方法,这个方法才是释放锁唤醒其他线程的关键

  1. 释放锁
  2. 从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资源让给该方法的调用者然后当前线程进入睡眠状态。

(仅用于记录平时学习个人心得,如若有错恳请指教)