A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 杨锦 中级黑马   /  2012-8-5 18:04  /  1406 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 杨锦 于 2012-8-5 19:21 编辑

class Exercise {
public static void main(String args[]) {
  final Print p=new Print();
  new Thread() {
   public void run() {
   
    for(;;)
     p.printer1();
   
   }
  }.start();
  
  new Thread() {
   public void run() {
   
    for(;;)
     p.printer2();
   
   }
  }.start();
}
}
class Print {
private int flag=1;
private Object obj = new Object();
public  void  printer1(){
  synchronized(obj){                    //用 synchronized代码块就会报异常
  if(flag==2)
  try{
          wait();
   }catch(Exception e){
   e.printStackTrace();
   }  
  System.out.println("黑");
  System.out.println("马");
  System.out.println("最");
  System.out.println("牛");

          notify();
  flag=2;
}
}

public  synchronized void printer2(){              //为什么用 synchronized方法就不报异常呢
   if(flag==1)
   try{
          wait();
  }catch(Exception e){
   e.printStackTrace();
   }
  System.out.println("I");
  System.out.println("L");
  System.out.println("O");
  System.out.println("V");
  System.out.println("E");
  System.out.println("Y");
  System.out.println("O");
  System.out.println("U");
  
         notify();
  flag=1;
  
}
}

     // 我已经try.....catch了啊,为什么还一直报异常!!!!

QQ截图20120805180359.jpg (46.97 KB, 下载次数: 17)

QQ截图20120805180359.jpg

评分

参与人数 1技术分 +1 收起 理由
田建 + 1 赞一个!

查看全部评分

5 个回复

倒序浏览
wait()、notify()、notifyAll()这三个方法是必须写在同步块或同步函数中的。
因为这写方法是对持有锁的线程操作的。
只有同一个锁上的被等待线程,可以被同一个锁上的notify()唤醒,不可以被不同锁上的线程进行唤醒。
所以这些方法的前面都必须标明调用这个方法的锁。
用同步函数时,默认的锁是this.,也就是你程序中的p了。这时不用标明wait()和notify()方法前的锁也是可以的。
而同步代码块中是用的锁是obj,这是你就必须表明了。
但是这时,你的等待唤醒机制所是用的锁是不同的锁了。我认为你的程序虽然不会报错了,但是却达不到预期的效果了。
所以你可以在同步方法中都标明锁obj,也就是所有的wait()、notify()方法都写成obj.wait();obj.notify();
第二种解决方式当然就是全部写成同步方法了。这样最方便也最保险。

评分

参与人数 1技术分 +1 收起 理由
田建 + 1 赞一个!

查看全部评分

回复 使用道具 举报
class Exercise {
public static void main(String args[]) {
  final Print p=new Print();
  new Thread() {
   public void run() {
   
    for(;;)
     p.printer1();
   
   }
  }.start();
  
  new Thread() {
   public void run() {
   
    for(;;)
     p.printer2();
   
   }
  }.start();
}
}
class Print {
private int flag=1;
//private Object obj = new Object();
public  void  printer1(){
  synchronized(this){                    //用 synchronized代码块就会报异常
  // 你这里的对象和 下面的不同 应该用this 调用当前的对象 或者下面也用obj对象作为锁 你这个同步代码块和下面的同步方法用的不是相同的key 所以根本就不能同步
  if(flag==2)
  try{
          wait();
   }catch(Exception e){
   e.printStackTrace();
   }  
  System.out.println("黑");
  System.out.println("马");
  System.out.println("最");
  System.out.println("牛");

          notify();
  flag=2;
}
}

public  synchronized void printer2(){              //为什么用 synchronized方法就不报异常呢
   if(flag==1)
   try{                                                                                        //        你把同步代码块的key 用this 他们的key相同啦 就不报异常啦
          wait();
  }catch(Exception e){
   e.printStackTrace();
   }
  System.out.println("I");
  System.out.println("L");
  System.out.println("O");
  System.out.println("V");
  System.out.println("E");
  System.out.println("Y");
  System.out.println("O");
  System.out.println("U");
  
         notify();
  flag=1;
  
}
}

点评

谢了!  发表于 2012-8-5 19:22

评分

参与人数 1技术分 +1 收起 理由
田建 + 1 赞一个!

查看全部评分

回复 使用道具 举报
补充下 上面的key指的是所调用对象
回复 使用道具 举报
汗。去文档查查你的异常,非法的监视器状态异常,原因就是同步代码块使用的锁是obj,而你的wait(),notify()调用时用的是this,而他们的调用需要你用你的所对象才可以。而同步方法用的锁对象就是this,所以就不会报告异常了。
回复 使用道具 举报
本帖最后由 张雪磊 于 2012-8-5 19:30 编辑

这个实际上是线程通信的问题,你的这个代码是在printer1线程和printer2之间进行相互唤醒的通信。这时候必须保证两个同步代码块使用同一把锁,而楼主的两个代码块一个使用的是obj锁,一个用的是this锁,也就是说这两个线程实际上并未同步,还在各自执行自己的run方法内容。
另外就需要了解notify,natifyAll,wait这三个方法了
这三个方法使用时,当前线程必须是当前对象锁资源的持有者,否则就会报IllegalMonitorStateException这个错误。由于两个代码块持有的锁资源不同,为实现同步,就报错了。
如果了解IllegalMonitorStateException 这个错误在上面时候下出现就容易解决了,
这个异常会在三种情况下抛出:1>当前线程不含有当前对象的锁资源的时候,调用wait()方法;2>当前线程不含有当前对象的锁资源的时候,调用notify()方法。3>当前线程不含有当前对象的锁资源的时候,调用notifyAll()方法。如果楼主不想用同步函数,而要用同步代码块的话,用下面这种写法就不会报错了。

class Exercise {
public static void main(String args[]) {
  final Print p=new Print();
  new Thread() {
   public void run() {

    for(;;)
     p.printer1();

   }
  }.start();

  new Thread() {
   public void run() {

    for(;;)
     p.printer2();

   }
  }.start();
}
}
class Print {
private int flag=1;
private Object obj = new Object();
public void  printer1(){
  synchronized(obj){                   //用 synchronized代码块就会报异常
  if(flag==2)
  try{
          obj.wait();//注意蓝色的部分必须加上obj.否则还会报错,这时候锁变成obj而不是this了,如果你省略那默认还是this,但实际上用的是obj锁而不是this,所以必须写上obj.
   }catch(Exception e){
   e.printStackTrace();
   }  
  System.out.println("黑");
  System.out.println("马");
  System.out.println("最");
  System.out.println("牛");

         obj.notify();
  flag=2;

}
}

public  void printer2(){              //为什么用 synchronized方法就不报异常呢
    synchronized(obj){
    if(flag==1)
   try{
         obj. wait();
  }catch(Exception e){
   e.printStackTrace();
   }
  System.out.println("I");
  System.out.println("L");
  System.out.println("O");
  System.out.println("V");
  System.out.println("E");
  System.out.println("Y");
  System.out.println("O");
  System.out.println("U");

         obj.notify();
  flag=1;
    }
}
}

评分

参与人数 1技术分 +1 收起 理由
田建 + 1 赞一个!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马