Java中的线程休眠大法系列(二)Object.wait()

目录

 

前言

上一篇文章说了Thread.sleep()背后的原理和各种案例,今天我们来研究一下java的另外一种使线程休眠的方法Object.wait()。 


一、看看JDK的注释上都说了什么

/**
     * Causes the current thread to wait until another thread invokes the
     * {@link java.lang.Object#notify()} method or the
     * {@link java.lang.Object#notifyAll()} method for this object.

    翻译:此方法会导致当前线程进入 wait 状态,直到其他线程调用了notify() 方法或者notifyAll()方法
     * In other words, this method behaves exactly as if it simply
     * performs the call {@code wait(0)}.
     * 
    翻译:换句话说,这个方法就是调用了  wait(0) ,也就是默认参数是0
     * The current thread must own this object's monitor. The thread
     * releases ownership of this monitor and waits until another thread
     * notifies threads waiting on this object's monitor to wake up
     * either through a call to the {@code notify} method or the
     * {@code notifyAll} method. The thread then waits until it can
     * re-obtain ownership of the monitor and resumes execution.
     * <p>
    翻译:当线程一定是要获取了该对象的 monitor 才能调用。调用方法后,线程会释放掉
对象的 monitor,然后进入waits状态,一直到其他的线程通过 notify()或者notifyAll() 方法通知
那些等待竞争获取该对象的monitor的线程们,进入唤醒状态。线程会一直等待,直到重新获取到对象
的monitor后,才能继续执行。

     * As in the one argument version, interrupts and spurious wakeups are
     * possible, and this method should always be used in a loop:
     * <pre>
     *     synchronized (obj) {
     *         while (&lt;condition does not hold&gt;)
     *             obj.wait();
     *         ... // 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.
     *
     * @throws  IllegalMonitorStateException  if the current thread is not
     *               the owner of the object's monitor.

翻译: 如果当前线程没有获取到 对象的monitor,会抛出 IllegalMonitorStateException异常
     * @throws  InterruptedException if any thread interrupted the
     *             current thread before or while the current thread
     *             was waiting for a notification.  The <i>interrupted
     *             status</i> of the current thread is cleared when
     *             this exception is thrown.
翻译:当其他线程 打断该线程的时候, 会抛出InterruptedException异常, 当异常抛出的时候,
打断状态就会被清除掉。(这点和 Thread.sleep() 方法抛出的异常一致)
     * @see        java.lang.Object#notify()
     * @see        java.lang.Object#notifyAll()
     */
    public final void wait() throws InterruptedException {
        wait(0);
    }

二、案例

1.一个案例说明全部问题

代码如下(示例):

package com.kinyang.objectwait;

import java.util.Scanner;

/**
 * @author KinYang.Liu
 * @date 2021/6/11 2:02 下午
 */
public class ObjectWaitTest {
    private static Object monitor = new Object();
    public static void main(String[] args) throws InterruptedException {
         创建一个 t1 线程
        Thread t1 = new Thread(() -> {

            synchronized (monitor){
                try {
                    System.out.println("t1 线程调用wait方法,进入休眠");
                    monitor.wait();
                    System.out.println("t1 线程,被唤醒了,继续执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t1-thread");
         启动t1线程
        t1.start();
        Thread.sleep(3000L);
        System.out.println("查看一下 t1 线程当前的状态:"+t1.getState());
        synchronized (monitor){
            System.out.println("main线程 获得了锁,然后调用 notify方法");
            monitor.notify();
        }



        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            if (scanner.nextLine().equalsIgnoreCase("bye")){
                System.out.println("再见");
                break;
            }else {
                System.out.println("指令错误");
            }

        }
    }
}

执行结果

从结果我们可以知道,t1线程调用 wait方法后,线程会进入 WAITING状态,然后其他线程调用 notify方法后,t1线程又被唤醒,重新进入执行状态。

所以wait方法一定要结合着notify一起来使用,而且,wait方法一定是放在synchronized代码里面执行,也就是当前线程必须获取到了 对象的monitor,才能执行对象的wait方法。

另外,方法也会抛出一个InterruptedException异常,和Thread.sleeep一样,当休眠的时候,如果被打断,也会抛出异常,并且打断状态也会被清除,具体可以参考上一篇Thread.sleep的InterruptedException案例分析。

如果wait()方法,指定了参数的话,表示的是休眠多久的意思(没有参数或者参数是0表示没有时间限制),在超过时间后,线程自动唤醒,然后去竞争锁,获取了,就继续执行,没有获取就继续等待。如果wait有参数的话,线程进入的是 TIMED_WAITING状态,不是WAITING状态。

从执行顺序上来看,也验证了wait方法会释放锁,否则的话,“main线程 获得了锁,然后调用 notify方法” 这句话就不会打印,notify()方法也不会执行,那么t1线程就会一直等待,就死锁了。所以wait方法一定是要释放到当前线程所持有的锁的。

这样一定也和Thread.sleep()有这本质区别。


总结

总结一下:

Object.wait()和Object.notify()一定是配合使用的,必须放在的synchronized代码块或者方法里,wait方法会导致线程释放锁,进入WAITING状态或者TIMED_WAITING状态(取决于是否设置了时间)。

当进入WAITING状态的时候,只能通过其他线程调用notify()方法唤醒,线程被唤醒后,需要重新竞争锁,获取到锁后,才能执行,如果获取失败,还会是进入WAITING状态。

当进入TIMED_WAITING状态的时候,除了上面说的notify()方法唤醒后,时间到了也会自动唤醒,唤醒后还是重新竞争锁,获取到锁后,才能执行,如果获取失败,还会是进入WAITING状态。

Object.wait()也会抛出InterruptedException异常,这点和Thread.sleep()方法一样。当线程被打断抛出异常后,打断状态也会被清除。

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jianyang.liu

从来没收到过一分钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值