java多线程并发之wait、nitifyAll方法

一、前言

在上篇博客中介绍了synchronized的常见操作,不过还有一点没有介绍到,那就是关于线程的等待和唤醒,因此本篇就介绍这两个方法

二、由来

在介绍wait、notify方法之前,我们需要知道为什么会有这个方法。在Java中,每个对象都有个对象锁标志(Object lock flag)与之相关联,当一个线程A调用对象的一段synchronized代码时,
它首先要获取与这个对象关联的对象锁标志,然后执行相应的代码,执行结束后,把这个对象锁标志返回给对象;因此,在线程A执行
synchronized代码期间,此时在 synchronized的方法中调用了sleep方法,如果另一个线程B也要执行同一对象的一段synchronized代码时(不一定与线程A执行的相同),它将 要等到线程A执行完后,才能继续。这样就造成了阻塞。

  • wait:导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法.wait会释放占有的锁,notify和notifyAll不会释放占用的锁.
  • void notifyAll():唤醒在此对象监视器上等待的所有线程。
  • void notify():唤醒在此对象监视器上等待的某一个线程.如果有多个,具体是哪一个可以认为是不确定的.

注意:以上三个方法都是本地方法,不可以被重写

三、Demo

public class WaitNotifyTest {
    public static Class lock = WaitNotifyTest.class;

    public static void main(String[] args) throws Exception {
        new TestThread2().start();
        new TestThread2().start();
        Thread.sleep(3000);
        synchronized (WaitNotifyTest.lock) {
            try {
                System.out.println(Thread.currentThread().getName() + " sent notification all");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
class TestThread2 extends Thread {

    public void run() {
        synchronized (WaitNotifyTest.lock) {
            System.out.println(Thread.currentThread().getName() + " wait for notification");
            try {
                WaitNotifyTest.lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " wake up");
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " doing " + i);
        }
    }
}

在上述代码中,首先开启两个线程,并且在run方法里调用全局琐的wait方法,接着输出如下:

Thread-0 wait for notification
Thread-1 wait for notification
main sent notification all

注意:此时程序并没有退出,因为两个线程都调用了wait方法,导致当前的线程等待。那么怎么可以唤醒wait方法的线程。接着看:

    public static void main(String[] args) throws Exception {
        new TestThread2().start();
        new TestThread2().start();
        Thread.sleep(3000);
        synchronized (WaitNotifyTest.lock) {
            try {
                System.out.println(Thread.currentThread().getName() + " sent notification all");
                WaitNotifyTest.lock.notifyAll();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

只需要在main方法里面添加notifyAll(),输出如下:

Thread-0 wait for notification
Thread-1 wait for notification
main sent notification all
Thread-1 wake up
Thread-0 wake up
Thread-1 doing 0
Thread-0 doing 0
Thread-0 doing 1
Thread-1 doing 1
Thread-0 doing 2
Thread-1 doing 2

此时,程序完整退出。notifyAll()唤醒所有线程。

注意:我们使用什么锁,就需要使用什么锁来让其线程等待和唤醒,否则会报错。

java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at com.lw.thread.dielock.TestThread2.run(WaitNotifyTest.java:33)

一个线程被唤醒不代表立即获取了对象的monitor,只有等调用完notify()或者notifyAll()并退出synchronized块,释放对象锁后,其余线程才可获得锁执行。

四、总结

本篇主要介绍了wait、nofity等方法的作用和注意事项。下一篇将会介绍lock方面的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值