堆栈花园的多线程学习备忘录——wait和notify

一、等待/通知机制

什么是等待/通知机制?

  • 在单线程中,如果要执行的代码需要满足一定条件才能执行,可以放到if语句块里。
  • 但在多线程中,可能A线程的执行的条件暂时没有满足,稍后B线程执行到一定程度,使得A线程的执行条件满足,再执行完A线程。可以将A线程先暂停,直到条件满足后再将A线程唤醒。
二、 等待通知机制的实现

Object类中有一个wait()方法,可以使执行的当前代码线程等待,暂停执行,直到接到通知,或者被中断。
注意:
(1)wait()方法只能在同步代码块中由锁对象调用。
(2)调用wait()方法后,当前线程会暂停,并释放锁对象。

Object类的notify()可以唤醒线程,该方法也必须在同步代码块中由锁对象调用(不然会抛异常)。如果有多个等待的线程,notify()方法只能唤醒其中一个。在同步代码块中调用notify()方法,不会立马释放锁对象,需要等当前同步代码块执行完,才会释放,所以我们一般把notify()放在同步代码块的最后。

  • 通过等待通知机制,实现2个线程交换打印输出奇数和偶数。
//先写一个多个线程需要共享的同一个对象的类。
public class Num{
    int i;
}

//专门打印偶数的线程
public class Even implements Runnable{
    Num num;
    public Even(Num num) {
        this.num = num;
    }
    @Override
    public void run() {
        while (num.i < 100){
            synchronized (num){
                if(num.i % 2 != 0){
                    try {
                        num.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "---->" + num.i);
                num.i++;
                num.notify();
            }
        }
    }
}

//专门打印奇数的线程
public class Odd implements Runnable{
    Num num;
    public Odd(Num num) {
        this.num = num;
    }
    @Override
    public void run() {
        while(num.i < 100){
            synchronized (num){
                if(num.i % 2 == 0){
                    try {
                        num.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "---->" + num.i);
                num.i++;
                num.notify();
            }
        }
    }
}

//main方法测试一下
public static void main(String[] args) {
        Num num = new Num();
        Thread t1 = new Thread(new Odd(num));
        Thread t2 = new Thread(new Even(num));
        t1.setName("t1");
        t2.setName("t2");
        t1.start();
        t2.start();
    }

分析一下以上代码:

  • 我们将奇数线程记作A线程,偶数线程记作B线程

当创建出这两个线程后,启动他们,如果A抢到了时间片,那么由于i的初始值为0,符合A中代码块的if语句,所以执行锁对象的wait方法,A开始等待(即使A第二次又抢到了时间片,还是会继续执行wait方法开始等待)。当B抢到了时间片,由于i不满足if语句,所以i自增,再执行锁对象的notify方法,另外一个共享锁对象的A就会被唤醒(若有多个这样的A线程,究竟唤醒哪个线程是不一定的),开始执行,由于这时的i是1,不满足if语句,所以i自增,并唤醒另一个共享锁对象的B。周而复始,实现了两个线程交替打印奇数和偶数。

三、 interrupt()方法会中断wait()
  • 当线程处于wait()等待状态时,调用线程对象的interrupt()方法会中断线程的等待状态。(是通过抛异常的方式中断,InterruptedException异常)
四、notify()和notifyAll()
  • notify()一次只能唤醒一个线程,如果有多个等待的线程,只会随机唤醒其中的某一个(这被称为信号丢失),想要所有等待线程都被唤醒,需要调用notifyAll()。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值