多线程中wait()与notify()和sleep()的区别

前言

今天又来讲讲我们之前只讲了一点的Javaee基础知识,今天要理解的是wait与notify,关于多线程这两个方法我们也是要理解的,那么我们今天就开始来深入理解一下。

wiat与notify的简单认识

wait和notify是Object类的方法,也就是任何对象都会存在这两个方法。那么这两个方法存在的意义是什么呢?

首先我们要知道操作系统对线程的执行时随机的,即抢占式的方式,我们无法预知哪个线程先执行哪个线程后执行,那么这时使用wait和notify,就可以实现控制线程的执行顺序,后执行的程序就可以先调用wait方法等待,让其他线程先执行。

wait的作用:使当前执行代码的线程进行等待,停止继续运行(把线程放入等待队列中),且释放锁,释放资源,让其他线程可以开始获取锁。需要注意的是wait是要在synchronized中使用的,否则就会抛出异常

notify:发出通知唤醒对象头为当前对象的,处于等待状态过程中的线程。

wait()方法详解

首先再次讲述一下wait()方法的功能:

  1. 停止当前执行代码的线程进入等待状态,将其放入等待队列中。
  2. 释放当前的锁,释放cpu资源。
  3. 当满足一定条件时,会重新获取这个锁。

那么唤醒有哪些条件呢?

  1. 首先就是其它线程notify
  2. 等待时间已经到了,wait方法是可以指定时间的wiat(long timeout)。
  3. 其他线程调⽤该等待线程的 interrupted ⽅法, 导致 wait 抛出 InterruptedException 异常.

那么下面我们演示一下基本的wait()方法的使用:

public class Main {

    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        synchronized (object) {
            System.out.println("等待中");
            object.wait();
            System.out.println("等待结束");
        }
    }
}

如上代码我们这么写就是死等,如果没有其它线程来唤醒,或者调用其interrupted()方法,他就会一直等待下去。

notify()方法详解

notify的功能:

唤醒其它处于等待状态的线程(属于该对象头的线程)

注意事项:

notify也需要在synchronized中使用。

首先我们得如果要唤醒得对象有多个,那么这时唤醒的线程也是随机的(没有“先来后到的说法”)

其次我们的唤醒并不是执行完notify后就立马生效,而是需要等待notify处于的同步代码块执行完。即走出synchronized的大括号。

用代码更加直观的展示两个方法的使用:

我们创建了两个类,一个WaitTask,NotifyTask,并且重写了他们的run方法,具体就是通过他们的打印顺序给大家展示一下他们的执行顺序

public class Main {


    public static void main(String[] args) throws InterruptedException {
        Object locker = new Object();
        Thread t1 = new Thread(new WaitTask(locker));
        Thread t2 = new Thread(new NotifyTask(locker));
        t1.start();
        Thread.sleep(1000);
        t2.start();
    }


    static class WaitTask implements Runnable {
        private Object locker;

        public WaitTask(Object locker) {
            this.locker = locker;
        }

        @Override
        public void run() {
            synchronized (locker) {
                while (true) {

                    try {
                        System.out.println("wait 开始");
                        locker.wait();
                        System.out.println("wait 结束");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    static class NotifyTask implements Runnable {
        private Object locker;

        public NotifyTask(Object locker) {
            this.locker = locker;
        }

        @Override
        public void run() {
            synchronized (locker) {
                System.out.println("notify 开始");
                locker.notify();
                System.out.println("notify 结束");
            }
        }
    }

}

notifyAll方法

作用与notify相似,但他会将等待的线程全部唤醒,但是唤醒的顺序还是随机的。

面试常考:

特性

wait()

sleep()

类所属

Object

Thread

调用位置

必须在同步方法或同步代码块中调用

可以在任何地方调用

释放锁

会释放锁

不释放锁

唤醒机制

需要 notify() 或 notifyAll() 唤醒

自动恢复执行,不需要唤醒机制

用途

线程通信与协作(如生产者-消费者模式)

控制线程的暂停时间

总的来说,wait() 主要用于线程间的协作和通信,sleep() 主要用于线程的暂停控制,二者的功能和使用场景有很大的不同。

你可能感兴趣的:(JavaEE部分,java,jvm,开发语言)