/*编写一个Java应用程序,要求有3个线程:studentl、student2和teacher,其中线程studentl准备“睡”20分钟后再开始上课,
线程student2准备“睡”一小时后再开始上课。teacher在输出4句“上课”后,“唤醒”了休眠的线程studentl;
线程studentl被“唤醒”后,负责再“唤醒”休眠的线程student2。*/
class WakeStudent{
public static void main(String[] args){
  Wake wake = new Wake();
  Thread student1, student2, teacher;
  student1 = new Thread(wake);
  student1.setName("shuishen1");  //睡神一
  student2 = new Thread(wake);
  student2.setName("shuishen2"); //睡神二
  teacher = new Thread(wake);
  teacher.setName("disruptsleep");//睡神杀手。
  
  student1.start();
  student2.start();
  teacher.start();           //启动三个进程(刚编的时候忘了写,要注意!!!)
}
}class Wake implements Runnable{
public static int alert = 0;   //0为安全;1为老师发飙;2为学生student1被叫醒,然后student1不得不叫旁边睡觉的student2 public void run(){
  String name = Thread.currentThread().getName(); 
  //线程student1 
  if(name.equals("shuishen1")){
    while (alert == 0) {
     System.out.println("睡神一说:先睡20分钟再说,反正这老师也不点名");
try { 
  wait(); // 如果老师没发飙必须等待
} catch (InterruptedException e){
}
}

while(alert == 1){
  System.out.println("睡神一说:我起来听课了,我去叫旁边的睡神二");
  notifyAll();
  alert = 2;
}
  }
  //线程student2
  if(name.equals("shuishen2")){
    
     if(alert != 2) {
     System.out.println("睡神二说:先睡一个小时再说,老师点名了有睡神一叫我起来");
try {
wait(); // 如果睡神一没提醒他则必须等待
} catch (InterruptedException e) {
}
}else{
  System.out.println("老师和睡神一都在看我,不好不起来听课了!");
}
  }
  //线程teacher
  if(name.equals("disruptsleep")){
    for(int i = 0; i < 4 ;i++){
      System.out.println("上课!!!不准睡觉!!!");
    }
    alert = 1;
    //notifyAll();
  }

}提示出现错误。Exception in thread "shuishen1"上课!不准睡觉!!java.lang.illegalMonitorStateException
at java.lang.object.wait<Native Method>
at java.lang.Object.wait(Object.java:485)

解决方案 »

  1.   

    首先说下wait(),notify(),notifyAll()这三个方法只有在同步方法或语句多的情况下才能用。你可以用yield这个方法/*编写一个Java应用程序,要求有3个线程:studentl、student2和teacher,其中线程studentl准备“睡”20分钟后再开始上课, 
     线程student2准备“睡”一小时后再开始上课。teacher在输出4句“上课”后,“唤醒”了休眠的线程studentl; 
     线程studentl被“唤醒”后,负责再“唤醒”休眠的线程student2。*/
    class WakeStudent {
    public static void main(String[] args) {
    Wake wake = new Wake();
    Thread student1, student2, teacher;
    student1 = new Thread(wake);
    student1.setName("shuishen1"); // 睡神一
    student2 = new Thread(wake);
    student2.setName("shuishen2"); // 睡神二
    teacher = new Thread(wake);
    teacher.setName("disruptsleep");// 睡神杀手。 student1.start();
    student2.start();
    teacher.start(); // 启动三个进程(刚编的时候忘了写,要注意!!!)
    }
    }class Wake implements Runnable {
    public static int alert = 0; // 0为安全;1为老师发飙;2为学生student1被叫醒,然后student1不得不叫旁边睡觉的student2 public void run() {
    String name = Thread.currentThread().getName();
    // 线程student1
    if (name.equals("shuishen1")) {
    while (alert == 0) {
    System.out.println("睡神一说:先睡20分钟再说,反正这老师也不点名");
    Thread.yield();
    } while (alert == 1) {
    System.out.println("睡神一说:我起来听课了,我去叫旁边的睡神二");
    alert = 2;
    }
    }
    // 线程student2
    if (name.equals("shuishen2")) { if (alert != 2) {
    System.out.println("睡神二说:先睡一个小时再说,老师点名了有睡神一叫我起来");
    Thread.yield();
    }
     else {
    System.out.println("老师和睡神一都在看我,不好不起来听课了!");
    }
    }
    // 线程teacher
    if (name.equals("disruptsleep")) {
    for (int i = 0; i < 4; i++) {
    System.out.println("上课!!!不准睡觉!!!");
    }
    alert = 1;
    }
    }
    }
      

  2.   

    楼主还没有理解wait, notify, notifyAll 的意义wait的意思就是,当前的线程在调用wait的对象上进行等待,而在调用对象的wait方法之前,必须先得到这个对象的“锁”,否则JVM会抛出楼主所说的异常。而在调用了对象的 wait 方法之后,当前的线程会暂时释放所得到的锁,直到其它线程在这个对象上调用notify或notifyAll方法之后,当前线程将被叫醒,并且重新得到互斥锁。举个简单又好理解的例子,一家商店有库存,它提供三个方法分别用于销售、进货和得到库存信息,代码如下:class Shop{
        // 商品的库存量
        private int goodsCount = 10;
        // 得到商品的库存量
        public int getGoodsCount(){
            return goodsCount;
        }
        // 出售一件商品
        public void sale(){
            if(goodsCount <= 0){
               System.out.println("商品已经买完,还未进货");
               return;
            }
            System.out.println("购买一件商品");
            this.goodsCount--;
        }
        // 进货
        public void incoming(int count){
            goodsCount += count;
        }
    }当某个线程在这家商店购买商品时,先得到商店的互斥锁,并判断商店库存是否大于0,如果大于0则购买商品,否则等待这家商店进货:Shop shop = ...... // 得到这家商店对象的引用
    synchronized(shop){
        try{
            while(shop.getGoodsCount() <= 0){
                shop.wait();
            }
            shop.sale();
        }catch(Exception ex){
        }
    }这其实也很好理解,某人进入一家商店买东西时,商店只对你服务,其他想买东西的人在后面排队,因此认为你得到了互斥锁
    如果商品库存大于0,则顺利地买到你想要的东西,而如果商品的库存不够时,你只能等待,并且让商店去干别的事情(比如为在你后面排队的人服务,或者去进货),也就是说你应该释放你的互斥锁,并且等待,这就是调用wait方法的作用。
    而当其它线程调用了商店的进货方法之后,并且调用这家商店的notify或notifyAll方法之后,购买商品的线程将被叫醒,并且在wait方法之后继续运行。首先应该要注意到,这三个方法都是 Object 类就已经定义了的,而不是在 Thread 和 Runnable 接口中定义的。也就是说wait、notify、notifyAll 是针对对象,而不是针对类。在如上的例子中,如果商店有几家,则在不同的商店上进行wait时,结果也不一样。另外,在调用wait前要先得到互斥锁,这也好理解,如果没有进行同步,对象的一些状态可能被其它的线程改变还有就是,在调用wait方法时,有一个while循环检查对象的状态。这是因为wait之后,释放了对象的锁,而释放锁之后可能改变对象的状态。比如在前面的例子中,在库存为0时有10个客人在等待购买商品,那么将会有10个线程在等待商店进货,而某次进货线程只进了5件商品,那么在进货线程调用notfiyAll叫醒这10个等待购买商品的线程当中,只有前5个线程能够跳出while循环,后面5个线程还得接着等待。这其实是合理的。