Java-Notify、NotifyAll、Wait使用

本文详细介绍了Java多线程中Notify、NotifyAll与Wait方法的使用,包括它们的区别、如何在Synchronized环境中正确调用,以及在生产者/消费者模式中的应用案例。

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

上篇文章中学到了Synchronized的使用,这篇文章就介绍一下Notify、NotifyAll、Wait。

1.Notify、NotifyAll、Wait

这三个方法均属于Object类,但是它们多用在多线程中。

三者的区别以及各自的含义(使用的注意事项):

  1. notify: 唤醒一个正在wait当前对象锁的线程,并继续执行
  2. notifyAll:唤醒全部在wait当前对象锁的线程,所有线程依然要进行锁竞争后才能执行
  3. wait:是当前线程释放对象所拥有的,并等待notify唤起继续执行
  4. wait/notify/notifyAll 都属于Object类不属于Thread类(三个方法都必须在synchronized(obj){}同步代码块中才能调用)
  5. notify是本地方法,具体唤醒哪个线程由虚拟机控制;
2.使用

它们通常配合Synchronized进行多线程间的通信以及调度。

案例一:5个线程同时竞争同一个对象的非静态Synchronized方法,通过notofy/notifyAll/wait进行调度

public class Notify_Wait_NotifyAll {
    public synchronized void test() {
        System.out.println("start:-------------");
        try {
            wait();//释放锁,进入等待状态,等待唤醒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end:-------------");
    }

    public static void main(String[] args) {
        Notify_Wait_NotifyAll test = new Notify_Wait_NotifyAll();
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    test.test();
                }
            }).start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("唤醒一个线程:-----------------");
        synchronized (test) {
            test.notify();//唤醒   在有锁的基础上
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("唤醒全部:---------------------");
        synchronized (test) {
            test.notifyAll();
        }
    }
}

运行结果:

start:-------------
start:-------------
start:-------------
start:-------------
start:-------------
notify one:-----------------
end:-------------
notify all:---------------------
end:-------------
end:-------------
end:-------------
end:-------------

观察可以发现,所有使用wait/notify/notifyAll的前提都是在有锁的基础上。

案例二:通过生产者/消费者模式进行产生消息/消费消息(使用它们进行线程间的调度)

public class Message {
    private String content;

    public Message(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}



//消费者
public class Consumer extends Thread{
    private Producer producer;
    private String name;

    public Consumer(Producer producer, String name) {
        super(name);
        this.producer = producer;
    }

    @Override
    public void run() {
        while(true){
            Message msg = producer.waitMessage();
            System.out.println(getName()+":"+msg.getContent());
        }
    }
}

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

//生产者,每隔三秒钟创建一条消息
public class Producer extends Thread {
    private List<Message> messages = new ArrayList<>();

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
        Random random = new Random(100);
        while (true) {
            try {
                Thread.sleep(3000);
                Message msg = new Message("message:" + random.nextInt(100));
                synchronized (messages) {
                    //System.out.println("-----产生一条消息-----");
                    messages.add(msg);
                    messages.notify();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public Message waitMessage() {
        synchronized (messages) {
            while (messages.size() == 0) {
                try {
                    //System.out.println("-----等待一条消息-----");
                    messages.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return messages.remove(0);
        }
    }
}

//////使用

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        ExecutorService service = Executors.newFixedThreadPool(5);
        Producer producer = new Producer();
        service.execute(producer);
        //producer.run();
        service.execute(new Consumer(producer,"c1"));
        service.execute(new Consumer(producer,"c2"));
        service.execute(new Consumer(producer,"c3"));
        service.execute(new Consumer(producer,"c4"));
    }
}

运行结果:

c1:message:15
c2:message:50
c3:message:74
c4:message:88
。。。

参考:
https://blog.youkuaiyun.com/summerzbh123/article/details/80632219
https://www.jianshu.com/p/f7d4819b7b24

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值