Java中的wait/notify、join/yield、park/unpark原理

一、wait和notify(Synchronized)

  • Owner 线程发现条件不满足,调用 wait 方法,即可进入 WaitSet 变为 WAITING 状态
  • BLOCKED WAITING 的线程都处于阻塞状态,不占用 CPU 时间片
  • BLOCKED 线程会在 Owner 线程释放锁时唤醒
  • WAITING 线程会在 Owner 线程调用 notify notifyAll 时唤醒,但唤醒后并不意味者立刻获得锁,仍需进入 EntryList 重新竞争

sleep(long n)和wait(long n)的区别

  • sleep是Thread方法,而wait是Object的方法
  • sleep不需要强制和synchronized配合使用,但wait需要和Synchronized一起用
  • sleep在睡眠的同时,不会释放对象锁,而wait在等待的时候会释放对象锁
  • 调用后线程状态都为TIMED_WAITING,wait中途被唤醒或者等待时间结束会进入BOLCKED(EntryList)重新竞争锁,但sleep结束后直接进入RUNNABLE状态,因为并没有释放掉锁,CPU可以直接使其运行(如果时间片轮到,或者有多余的线程核)。

二、join和yield

join的本质是让调用线程(执行t1.join()的线程)wait在当前线程对象实例(t1线程)上。调用线程在当前线程对象上进行等待,当线程执行完成后,被等待的线程就会在退出前调用notifyAll()通知所有的等待线程继续执行。因此,不应再Thread实例上使用类似wait()和notify()等方法,会影响系统API工作。

调用者轮询检查alive状态:

t1.join();

等价于下面代码

synchronized (t1) {
 // 调用者线程进入 t1 的 waitSet 等待, 直到 t1 运行结束
 while (t1.isAlive()) {
 t1.wait(0);
 }
}

yield会使当前线程让出CPU,会让当前线程从Running进入Runnable状态。但要注意,让出CPU并不代表当前线程不执行了。当前线程让出CPU之后,还会进行CPU资源的争夺,但是否能再次被分配到就不一定了。因此,对Thread.yield()的调用好像就是再说:我已经完成了一些做重要的工作了,我应该是可以休息一下了,给其他线程一些工作机会。

三、park和unpark

LockSupport类使用类似信号量的机制。他为每个线程准备了一个许可(初始值默认为0,不可用),如果许可可用,那么park()会立即返回,并且消费这个许可(也就是将许可变为不可用),如果许可不可用,就会阻塞。

unpark()则使得一个许可变为可用(但是和信号量不同的是,许可不能增加,你不可能拥有超过一个许可,它永远只有一个)

这个特点使得,即使unpark()操作发生在park()之前,它也可以使下一次的park()立即返回。

与Object的wait &notify相比

  • wait,notify和notifyAll必须配合Object Monitor(synchronized)一起使用,而unpark不必
  • park & unpark是以线程为单位来【阻塞】和【唤醒】线程,而notify只能随机唤醒一个等待线程,notifyAll是唤醒所有等待线程,就不那么【精确】
  • park & unpark可以先unpark,而wait & notify不能先notify

LockSupport.park()还能支持中断影响。但是和其他接收中断的函数很不一样,LockSupport.park()不会抛出InterruptedException异常。它只会默默返回,但会标记中断位。我们可以从Thread.intterrupted()等方法获得中断标记。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值