一、程序为什么报异常:
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