JAVA进阶 THREAD学习08 wait()和notify()方法

总述

个人感觉wait()和notify()方法的关系可以用“解铃还须系铃人”这句话来概括。
当一个线程对一个对象使用wait() 方法,即这个线程在等待这个对象,可以看成 “系铃” ;当这个对象使用了notify() 方法后,可以看成 “解铃” ,被这个对象“系铃”的线程就被唤醒了。
当然线程的notify唤醒是随机的,notify不能确定唤醒的线程,可以看成“系的铃”太多了,盲解一个应付。
那么如果需要这个对象“系铃”的所有线程全部唤醒就可以使用notifyAll(),notifyAll()唤醒的所有线程后,线程的运行不是按照顺序,而是需要重新竞争的。

wait()方法

wait()方法做的事

  • 使当前执行代码的线程进行等待(“系铃”). (即把线程放到等待队列中)
  • 释放当前的锁
  • 满足一定条件时被唤醒, 重新尝试获取这个锁.

wait()结束条件

  • 其他线程调用该对象的 notify 方法.(“解铃”,唤醒
  • wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).
  • 其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常.
    这里给个使用的例子:注意wait()和notify()需要和synchronized关键字“捆绑使用”否则报错。
public class JAVA_THREAD08 {
    public static void main(String[] args) throws InterruptedException{
        Object object=new Object();
        synchronized(object){
            System.out.println("start wait");
            object.wait(100);
            System.out.println("end wait");
        }
    }
}

运行结果是在打印完start wait后等待一秒再打印end wait。

notify()方法

顾名思义就是唤醒被wait沉睡的线程,(“解铃”被wait()“系铃”的线程)。

  • notify()方法必须在同步方法或者同步代码块中使用,用来“唤醒”可能在等待该对象的对象锁的其他线程,发送notify通知。 ( “解铃”解除该对象系的“铃”,当然这里的动作主体变了,这里的对象是主动,线程是被动“被系”;但其实在客观描述这个现象时,是这个对象被线程等待,线程是主动,对象是被动。这里是换了一个理解的角度)。
  • 如果有多个线程等待该对象,就随机唤醒一个。(没有“先来后到”)
  • 使用notify方法后不会立即释放同步锁,而是等到使用notify方法的线程或者notify所在的代码块全部执行完毕(结束运行)后才会释放(唤醒)。

使用例子:

   static class WaitDemo implements Runnable {
        private Object locker;

        public WaitDemo(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 NotifyDemo implements Runnable {
        private Object locker;

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

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

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

在这个例子中,wait等待在notify方法使用后才会停止。

notifyAll()

一次唤醒所有线程让他们竞争,也可以理解为一次性把所有系上的“铃”都”解铃“了。

wait()和sleep()的区别

  1. wait方法需要在synchronized的同步块或者同步方法才能使用,sleep方法不需要
  2. wait方法是Object的方法,sleep方法是Thread的静态方法

wait应用的例子详解——多线程打印ABC

思路是这样的,先新建三个变量,一个count限定次数,一个message限定当前打印的字母。在每个线程中都设定一个打印的字母,还有一个Object对象lock给线程等待(或者说“将线程系住”)
如果是这个字母,就打印输出这个字母,并把count++,唤醒所有的线程message换成下一个按顺序需要打印的字母。(由这个message的转换可以实现线程的顺序执行
如果不是这个字母,就进入一直将当前线程wait的循环。

所以每打印一次字母(或者说线程每执行一次自己需要执行的代码)都会经历一次所有线程竞争进行判断、然后等待,最后重新唤醒的过程。

public class JAVA_THREAD08 {
    private static String message = "A";
    private static Object lock = new Object();

    public static void main(String[] args) {

        new Thread(() -> {
            int count = 1;
            synchronized (lock) {
                while (count < 101) {

                    while (!message.equals("A")) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(message);
                    message = "B";
                    count = count + 1;
                    lock.notifyAll();
                }
            }
        }, "A").start();

        new Thread(() -> {
            int count = 1;
            synchronized (lock) {
                while (count < 101) {
                    while (!message.equals("B")) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(message);
                    message = "C";
                    count = count + 1;
                    lock.notifyAll();
                }
            }
        }, "B").start();
        
        new Thread(() -> {
            int count = 1;
            synchronized (lock) {
                while (count < 101) {
                    while (!message.equals("C")) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(message);
                    message = "A";
                    count = count + 1;
                    lock.notifyAll();
                }
            }

        }, "C").start();
    }
}


结果如下:
在这里插入图片描述

  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值