wait和notify&生产者消费者模式

一、程序为什么报异常:

package reflect;
​
import java.lang.reflect.Method;
//程序运行结果笔试题: 请问以下代码为什么报异常IllegalMonitorStateException
//提示: 线程中的notify()和wait()必须用在同步代码中  
synchronized(){ 用在这里}   (使用格式:  对象名.wait()  对象名.nitify() )
public class Test {
    public static void main(String[] args) throws Exception {
        Class p2= Person.class;
        Object p=p2.newInstance();
        //Method[] ms=p2.getDeclaredMethods();//不能访问父类方法(不能访问wait)
        Method[] ms=p2.getMethods();//能访问父类方法(能访问wait)
        for(Method m:ms){
            if(m.getParameterCount()==0) {
            //只调用Person中的无参方法(Person还有很多继承来的方法比如equals方法)
                m.setAccessible(true);
                m.invoke(p);
            }
        }
    }
}
​
​
​
class Person {
​
    public int getAge() {
        System.out.println("Person的getAge方法执行了");
        return 5;
    }
​
//    public final void wait() throws InterruptedException {
//        wait(0);//本方法是从父类Object中继承的方法
//    }
​
}

二、改进:

前提:线程中的notify()和wait()必须用在同步代码中 synchronized(){ 用在这里} (使用格式: 对象名.wait() 对象名.nitify() )

原因:

1.Method[] ms=p2.getMethods(); 会获取Person中的所有方法

2.m.invoke(p); 表示执行当前的方法。 当执行wait方法时就会报IllegalMonitorStateException异常

是因为线程中的notify()和wait()必须用在同步代码中 synchronized(){ 用在这里} (使用格式: 对象名.wait() 对象名.nitify() )

所以可以给执行方法的代码m.invoke(p); 加一个条件 "wait".equals(m.getName()) 如果方法名为wait就执行

synchronized (p) {
    m.setAccessible(true);
    m.invoke(p);
}

for循环代码改造后如下(其他代码不变):

for(Method m:ms){
    if(m.getParameterCount()==0) {
        if (!"wait".equals(m.getName())) {
            m.setAccessible(true);
            m.invoke(p);
        } else {
            synchronized (p) {
                m.setAccessible(true);
                m.invoke(p);//执行了getAge(), 和wait()方法,
                //然后因为执行wait()方法 程序阻塞住了(其他无参方法执行不了了)
            }
        }
    }
​
}

三、wait()和notify()正确用法

请参考下边内容(参考下边的一二三)

一、wait和notify用法:

wait()和notify()方法只能用在同步代码块中

A.wait()和notify()方法可以用在被synchronized修饰的方法中:

B.wait()和notify()方法可以在synchronized(){ } 代码块中调用:

二、代码说明:

吃包子案例
1.本案例演示的是(23种设计模式):生产者消费者模式
  A.生产者线程负责生产数据<生产包子: 包子数量减少>, 生产者生产包子
   (循环向集合buns集合中添加包子)
    生产者生产够10个包子就用wait方法进入阻塞,并调用notify方法唤醒消费者线程让其执行(吃包子)
  B.消费者线程负责消费数据<吃包子: 包子数量增加>,消费者消费包子
  (循环从集合buns中删除包子元素)
  如果buns集合中没有包子了就用wait方法进入阻塞,并调用notify方法唤醒生产者线程让其执行
  (继续生产包子)
 
最终执行效果: 生产者线程先执行生产包子 生产够10个后等待, 然后消费者线程后执行消费包子 消费完等待, 然后让生产者线程继续执行。
  
注意:有兴趣的人可以找资料了解一下23种设计模式
2.本案例也是: wait()和notify()用法演示案例  //wait()和notify()方法必须用在线程同步的语法情景内(要用在synchronized内)

三、代码演示:

3.1.生产者线程:

class Boss_producer extends Thread{
    //1.Boss_producer类表示包子店老板,是生产者
    //2.List buns集合表示老板拥有的所有包子(此集合中放了很多包子对象)
    LinkedList buns;
​
    public Boss_producer(LinkedList buns) {
        this.buns = buns;
    }
​
​
    public void run() {
​
        //3.模拟做包子的过程:假设模拟制作5个包子就停下来
        //(表示已经没地方放包子了,需要等待消费
        // <够5个包子就调用wait方法表示老板线程Boss_producer阻塞>)
        while(true) {
            try {
                synchronized (buns) {
                    Thread.sleep(900);
                    while (buns.size() == 10) {
                        System.out.println("集合已满,不再生产包子了。"+
                                " 唤醒正在wait的线程(消费者线程)去消费(吃)包子");
                        buns.notify();//表示唤醒多个正在wait线程中的任意一个
                        //buns.notifyAll();//表示唤醒多个正在wait线程中的任意一个
                        buns.wait();
                    }
                    String uuid = UUID.randomUUID().toString().toUpperCase() + 
​​​​​​​                        "号包子";
                    System.out.println("Boss_producer.run:向buns集合添加"+uuid);
                    buns.add(uuid);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
​
    }
}

3.2.消费者线程:

class Consumer extends Thread{
    private LinkedList buns_eat=null;
​
    public Consumer(LinkedList buns) {
        this.buns_eat = buns;
    }
​
    public void run() {
        while(true){
​
            try{
                synchronized (buns_eat){
                    while(buns_eat.isEmpty()){
                        try {
                            System.out.println(Thread.currentThread().getName()
                                +"包子吃完了,等待出笼的新包子");
                            buns_eat.notify();
                            //唤醒另一个线程(生产者线程)继续运行(生产包子)
                            buns_eat.wait();//让buns_eat所属的对象阻塞
                            //(消费者线程阻塞)
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                    System.out.println("Consumer.run:从集合中取出包子消费"+
​​​​​​​                        buns_eat.remove());
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

3.3.测试类:

package com;
//吃包子案例
// (包子店老板生产10个包子然后阻塞,消费者就吃完10个包子然后阻塞,包子店老板再生产10个包子后又阻塞....)
//1.本案例演示的是(23种设计模式):生产者消费者模式
//  (生产者线程负责生产数据<生产包子: 包子数量减少>, 
//消费者线程负责消费数据<吃包子: 包子数量增加>)
//注意:有兴趣的人可以找资料了解一下23种设计模式
//2.本案例也是: wait()和notify()用法演示案例  //wait()和notify()方法必须用在线程同步的语法情景内(要用在synchronized内)
​
import java.util.LinkedList;
import java.util.UUID;
​
public class EatBunDemo {
​
    public static void main(String[] args) {
        LinkedList buns=new LinkedList();//存储包子的集合
        new Boss_producer(buns).start();
        new Consumer(buns).start();
    }
​
}


2022-06-06 zhaoYongQi

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值