线程间通信之等待唤醒机制

本文介绍了线程间的等待唤醒机制,包括共享内存和消息传递两种通信方式。详细解释了wait()、notify()及notifyAll()等方法的作用及使用细节,并通过示例展示了线程如何通过这些方法进行协调。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程间通信之等待唤醒机制

在命令式编程中,线程之间的通信机制有2种:共享内存和消息传递

在共享内存的并发模型里,线程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信。在消息传递的并发模型里,线程之间内有公共状态,线程之间必须通过发送消息来进行显示通信。

等待唤醒机制

等待唤醒机制,是指一个线程A调用了对象Object的wait()方法进入等待状态,而另一个线程B调用了对象Object的notify()或者notifyAll()方法,线程A收到了通知后,从对象Object的wait()方法返回,进而执行后续操作。

上述两个线程通过Object对象来完成交互,而对象上的wait()notify()/notifyAll()的关系就如同开关信号一样,用来完成等待方和通知方的交互工作。

等待/通知的相关方法是任意Java类对象都具备的,Object类都有实现

等待/通知的相关方法

  • notify(): 通知一个对象上等待的线程,使其从wait()方法返回,而返回的前提是该线程获得了对象的锁。

  • notifyAll():通知所有等待在该对象上的线程

  • wait():调用该方法的线程进入等待状态,只有等待另外的线程的通知或被中断才会返回,需要注意,调用wait()方法后,会释放对象锁。

  • wait(long mills):超时等待一段时间(单位毫秒),如果没有就超时返回。

  • wait(long mills , int n):对超时时间更细粒度的控制,可以达到纳秒

调用wait()notify()/notifyAll()需要注意的细节

  • 使用wait()notify()/notifyAll()时需要先对调用对象加锁

  • 调用wait()方法后,线程状态由运行状态(Running)变为等待状态(Waiting),并将当前线程放置到对象的等待队列。

  • notify()/notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()/notifyAll()的线程释放锁之后,等待线程才有机会从wait()返回。

  • notify()方法将等待队列中的一个等待线程移动到同步队列中,而notifyAll()方法则是将等待队列中所有的线程全部移到同步队列,被移动的线程有等待状态(Waiting)变为阻塞状态(Blocked)

  • wait()方法返回的前提是获得了调用对象的锁。

从上述细节中可以看到,等待唤醒机制依托于同步机制(同步对象锁),其目的就是确保wait()方法返回时能够感应到通知线程对变量做出修改。


在Thread的API与wait()有一个很像的方法sleep()方法,他们2者的区别如下:

sleep()在休眠的过程中是一直持有锁的,而wait()是执行之后释放锁的


等待/通知机制示例

public class Test {
    private final static Object lock = new Object();

    private static boolean flag = true;

    public static void main(String[] args) {
        ThreadA threadA = new ThreadA();
        threadA.setName("threadA");

        ThreadB threadB = new ThreadB();
        threadB.setName("threadB");

        threadA.start();
        threadB.start();

    }

    public static class ThreadA extends Thread {

        @Override
        public void run() {
            synchronized (lock) {
                while (flag) {
                    System.out.println(getName() + ":开始执行");
                    try {
                        System.out.println(getName() + ":进入等待状态");
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(getName() + ":执行结束");
            }
        }
    }

    public static class ThreadB extends Thread {

        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(getName() + ":开始执行");
                lock.notify();
                System.out.println(getName() + ":通知释放锁");
                flag = false;
                System.out.println(getName()+":执行结束");
            }
        }
    }

}

打印结果:

threadA:开始执行
threadA:进入等待状态
threadB:开始执行
threadB:通知释放锁
threadB:执行结束
threadA:执行结束

在这个示例中,ThreadA和ThreadB的状态描述:

当ThreadA线程获取了lock对象锁,然后调用lock.wait()方法。从而放弃了lock锁,ThraedA线程进入等待队列中(等待池),ThreadA进入等待状态。由于ThreadA释放了锁,此时ThreadB获得了lock锁,并调用notify()方法,ThreadA从等待队列(等待池)进入同步队列(锁池),此时ThreadA由等待状态(Waiting)变为阻塞状态(Blocked)。ThreadB释放了lock锁后,ThreadA再次获取了lock锁,wait()方法返回继续执行

image


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值