(Java并发基础)Object的wait/notify/notifyAll与Thread的关系

首先我们要知道Java中的每个类的父类都是Object,而Object中对象头中有个位置用来保存锁信息。这块将在高级部分进行深入讲解。

为什么wait方法必须在synchronized保护的同步代码中使用?

此方法会导致当前线程将自己放入该对象的等待集中,然后放弃对此对象的所有同步声明。线程T出于线程调度目的而被禁用,并处于休眠状态。其实就是让当前线程运行该该对象处,并让出CPU。

先来段源码,因为源码说要“该方法的调用必须是拥有对象的锁"。也就是通过synchronized方法或代码块获取对象的锁。但是为啥要这么设计呢?其实要从该方法的作用说起,该方法是让CPU让出,停在该对象处的等待队列中。如果不加锁,其他线程就可以随意进入该对象并修改该对象的状态。

     * <p>
     * A thread can also wake up without being notified, interrupted, or
     * timing out, a so-called <i>spurious wakeup</i>.  While this will rarely
     * occur in practice, applications must guard against it by testing for
     * the condition that should have caused the thread to be awakened, and
     * continuing to wait if the condition is not satisfied.  In other words,
     * waits should always occur in loops, like this one:
     * <pre>
     *     synchronized (obj) {
     *         while (&lt;condition does not hold&gt;)
     *             obj.wait(timeout);
     *         ... // Perform action appropriate to condition
     *     }
     * </pre>
     * * This method should only be called by a thread that is the owner
     * of this object's monitor. See the {@code notify} method for a
     * description of the ways in which a thread can become the owner of
     * a monitor. 

这里还存在一个“虚假唤醒”(spurious wakeup)的问题,线程可能在既没有被notify/notifyAll,也没有被中断或者超时的情况下被唤醒,这种唤醒是我们不希望看到的。虽然在实际生产中,虚假唤醒发生的概率很小,但是程序依然需要保证在发生虚假唤醒的时候的正确性,所以就需要采用while循环的结构。

while (condition does not hold)
    obj.wait();

这样即使被虚假唤醒,也会再次检查while里边的条件,如果不满足条件,就会继续wait,也就消除了虚假唤醒的风险。

为什么wait/notify/notifyAll被定义在Object类中,而Sleep定义在Thread类中?

主要有两点原因:

  1. 因为 Java 中每个对象都有一把称之为 monitor 监视器的锁,由于每个对象都可以上锁,这就要求在对象头中有一个用来保存锁信息的位置。这个锁是对象级别的,而非线程级别的,wait/notify/notifyAll 也都是锁级别的操作,它们的锁属于对象,所以把它们定义在 Object 类中是最合适,因为 Object 类是所有对象的父类。
    因为如果把 wait/notify/notifyAll 方法定义在 Thread 类中,会带来很大的局限性,比如一个线程可能持有多把锁,以便实现相互配合的复杂逻辑,假设此时 wait 方法定义在 Thread 类中,如何实现让一个线程持有多把锁呢?又如何明确线程等待的是哪把锁呢?既然我们是让当前线程去等待某个对象的锁,自然应该通过操作对象来实现,而不是操作线程。

wait/notify和sleep方法的异同?

主要对比 wait 和 sleep 方法,我们先说相同点:

  1. 它们都可以让线程阻塞。
  2. 它们都可以响应 interrupt 中断:在等待的过程中如果收到中断信号,都可以进行响应,并抛出 InterruptedException 异常。
    不同点:
  3. wait 方法必须在 synchronized 保护的代码中使用,而 sleep 方法并没有这个要求。
  4. 在同步代码中执行 sleep 方法时,并不会释放 monitor 锁,但执行 wait 方法时会主动释放 monitor 锁。
  5. sleep 方法中会要求必须定义一个时间,时间到期后会主动恢复,而对于没有参数的 wait 方法而言,意味着永久等待,直到被中断或被唤醒才能恢复,它并不会主动恢复。
  6. wait/notify 是 Object 类的方法,而 sleep 是 Thread 类的方法。
    以上就是关于 wait/notify 与 sleep 的异同点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值