JUC并发编程(4)——wait/notify,join原理,park/unpark

一、wait/notify

简介

wait会让拥有该锁对象的线程进行阻塞,同时释放锁。notify可以随机唤醒一个锁对象阻塞的线程

API

obj.wait():让进入object监视器的线程到waitSet等待,线程会释放锁。
obj.wait(long timeout):等待多少毫秒。
obj.notify():在object上正在waitSet等待的线程中挑一个唤醒,唤醒的线程需要去竞争。
obj.notifyAll():让object上正在waitSet等待的线程全部唤醒。

知识点

① 一旦调用了wait,偏量锁和轻量锁会膨胀成重量锁。
② wait和notify是object类的方法,wait和notify只能在同步块中被调用。

sleep和wait的区别

① sleep是Thread类的静态方法,wait是Object的方法
② sleep不需要强制和synchronized配合使用,但wait需要和synchronized一起使用
③ sleep时不释放对象锁,wait会释放对象锁
④ sleep和带参数的wait会使线程进入TIMED_WAITING,不带参数的wait会使线程进入WAITING
⑤ sleep方法需要参数,wait有没有参数都可以

二、join原理

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

① 当在一个线程A中调用另一个线程对象B的join方法。join方法是同步方法,它的锁对象为this也就是对象B。
② 当线程A进入同步方法,线程A也就获得了锁对象B。
③ while (isAlive())是防止虚假唤醒,例如当线程Await后,另一个线程C拿到了锁对象B,然后调用了B的notify把A唤醒了,但是线程B还没运行结束,这就是虚假唤醒。while (isAlive())保证率只有当线程B死亡时才能跳出循环。
④ 当一个线程结束时,会调用自身的notifyall


三、park/unpark

介绍

它们是LockSupport类中的方法

LockSupport.park();
LockSupport.unpark(暂停的线程对象);

park/unpark原理

① 每个线程底层都有一个parker对象,该对象由_counter,_cond,_mutex组成。

② 调用park时,判断_counter是否为0并且线程的打断标记位是否为false,满足这两个条件,才会阻塞当前线程。

③ 调用unpark时,将传入的线程对象的_counter设置为1。

④ park结束阻塞,并且将_counter设置为0。

park方法不阻塞的情况

如下两个条件任何一个成立,park()都不会阻塞:

中断标志位存在(wait、join、sleep或Thread.interrupted()都会清除中断标志位)
_counter为1(之前调用了unpark或者interrupt)

注意事项

① unpark方法可以在park方法之前或者之后调用都可以生效。它会唤醒最近一个park()
② unpark方法不能重复多个,应为每次park()方法结束时都会把_counter赋值为0
③ interrupt不仅会改变打断标记位,同时也会调用unpark方法。
④ 有时候,打断sleep、wait后。虽然打断标记位被重置为false,但是_counter仍然为1,所以后续的park()方法仍然会阻塞。
⑤ 简单来说,只有一种情况,会使多个park失效。即打断标记位始终为true。当打断标记位为false时,一个unpark只能唤醒一个park。

park和wait区别

① wait方法需要在synchronized中执行,LockSupport.park()可以在任意地方执行。
② wait方法会抛出异常,LockSupport.park()不会抛出异常
③ notify方法必须在wait后执行,才能唤醒,unpark方法可以在wait之后执行。
④ wait会释放锁,park不会释放锁。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值