wait和notify讲解,及3个线程搭配wait和notify连续输出10次ABC

一、背景介绍:

由于线程之间是抢占式执行的,因此线程之间执行的先后顺序难以预知,
但是实际开发中我们希望合理的协调多个线程之间的执行先后顺序。

比如如下代码,我们希望通过3个线程顺序打印出ABC。

public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
            System.out.println("A");
        });

        Thread t2=new Thread(()->{
            System.out.println("B");

        });

        Thread t3=new Thread(()->{
            System.out.println("C");
        });

        t1.start();
        t3.start();
        t2.start();
    }

**

输出结果:

**
输出截图

可见输出结果不是固定的,因为线程之间是抢占式执行,,哪一个线程先执行是不可预知的。

所以此时需要使用wait和notify两个方法搭配使协调3个线程工作。

完成这个协调工作,主要涉及到三个方法:

  • wait()/wait(long timeout):让当前线程进入等待状态

  • notify()/notifyAll():唤醒在当前对象上等待的线程

    注意:wait,notify,notifyAll 都是 Object 类的方法
    

二、wait方法介绍及基本用法:

wait做的事情:

  • 使当前执行代码的线程进行等待。(把线程放到等待队列中)

  • 释放当前的锁。

  • 满足一定条件时被唤醒,重新尝试获取这个锁。

     wait 要搭配 synchronized 来使用. 脱离 synchronized 使用 wait 会直接抛出异常.
    

wait结束等待的条件:

  • 其他线程调用该对象的notify方法
  • wait等待时间超时(wait方法提供一个带有timeout参数的版本,来指定等待时间)。
  • 其他线程调用该等待线程的 interrupted方法,导致wait抛出 InterruptedException 异常。

wait()方法的基本使用

    wait 要搭配 synchronized 来使用. 脱离 synchronized 使用 wait 会直接抛出异常.
public static void main(String[] args) throws InterruptedException {
        Object object=new Object();
        synchronized (object) {
            System.out.println("等待中");
            object.wait();  //使此线程阻塞   并且暂时把锁释放,  保证其他线程可以获取到object这个对象的锁
            System.out.println("等待结束");
        }
    }

在这里程序会在输出完 “等待中” 后一直等待下去。如果不要一直等待下去,就要搭配 notify()方法唤醒

三、notify方法介绍及基本用法:

notify方法是唤醒等待的线程。

  • 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的
    其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
  • 如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 “先来后到”)
  • 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行
    完,也就是退出同步代码块之后才会释放对象锁。

notify()方法的基本使用

 这里通过 t1线程 负责等待,用 t2线程 对其唤醒。
public static void main(String[] args) throws InterruptedException {
        Object object=new Object();

        Thread t1=new Thread(()->{
            //此线程负责进行等待
            System.out.println("t1:wait之前");
            try {
                synchronized (object) {
                    object.wait();          //对对象进行wait()操作,必须先获取到该对象的锁
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1:wait之后");
        });

        Thread t2=new Thread(()->{
            System.out.println("t2:notify之前");
            synchronized (object) {
                //notify 也必须先获取到锁  才能通知
                object.notify();
            }
            System.out.println("t2:notify之后");
        });

        t1.start();   
        Thread.sleep(500); //这里休眠500ms,目的为了保证让t1线程先获取到object对象的锁,然后进行wait等待
        t2.start();
    }

输出结果:
在这里插入图片描述

四、wait和notify 搭配用例:

有三个线程,分别只能打印ABC,要求按顺序打印ABC,打印10次。

要求:

在这里插入图片描述

使用synchronized、wait和notify

三个线程t1、t2、t3分别循环打印10次A、B、C,
打印C之前要先打印B, 所以在线程 t3 中打印C之前获取一把锁locker1,对其加锁! 当线程 t2 打印完B后对在锁locker1上等待的线程 t3 进行唤醒。A,B之间同理!

public static void main(String[] args) throws InterruptedException {
        //有三个线程,分别只能打印A,B和C
        //要求按顺序打印ABC,打印10次

        Object locker1=new Object();
        Object locker2=new Object();
        Object locker3=new Object();

        Thread t1=new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                synchronized (locker3){
                    try {
                        locker3.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.print("A");
                synchronized (locker2){
                    locker2.notify();
                }
            }
        });

        Thread t2=new Thread(()->{
            for (int i=0;i<10;i++) {
                synchronized (locker2){
                    try {
                        locker2.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.print("B");
                synchronized (locker1){
                    locker1.notify();
                }
            }
        });

        Thread t3=new Thread(()->{
            for (int i=0;i<10;i++) {
                synchronized (locker1){
                    try {
                        locker1.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("C");
                synchronized (locker3){
                    locker3.notify();
                }
            }
        });

        t1.start();
        t2.start();
        t3.start();

        Thread.sleep(1000);  //保证线程2、3先获取到locker1、2两个对象的锁
       
        //开始打印之前,要先保证线程t2、t3获取到locker1、2两个对象的锁
        synchronized (locker3){   //通知locker3 启动
            locker3.notify();
        }
    }

代码运行结果:
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值