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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 158803629 中级黑马   /  2015-7-28 16:22  /  3483 人查看  /  11 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

8黑马币
  1. package justForTest;


  2. class  threadAccess
  3. {    //两个线程同时访问一个资源
  4.         public static void main(String[] args)
  5.         {
  6.         resource r=new resource();
  7.                 new Thread(new input(r)).start();
  8.                 new Thread(new output(r)).start();
  9.         }
  10. }

  11. //存入资源线程
  12. class input implements Runnable
  13. {
  14.         private resource r;
  15.         input(resource r){
  16.          this.r=r;
  17.         }
  18.          public void run(){
  19.                  int i=0;
  20.                  
  21.                  while(true){
  22.                          if(r.flag){
  23.                                  try
  24.                                  {
  25.                                         r.wait();
  26.                                  }
  27.                                  catch (Exception e)
  28.                                  {
  29.                                          e.printStackTrace();
  30.                                  }
  31.                          }

  32.                          synchronized(r){
  33.                  if(i==0){
  34.                          r.name="liuliu";
  35.                          r.sex="nan";
  36.                  }
  37.                  else{
  38.                    r.name="yanyan";
  39.                    r.sex="lv";
  40.                  }
  41.          i=(1+i)%2;
  42.                  r.flag=true;
  43.                  r.notify();
  44.        }
  45.            }
  46.           
  47.          }
  48. }
  49. //取出资源线程
  50. class output implements Runnable
  51. {
  52.         private resource r;
  53.         output(resource r){
  54.          this.r=r;
  55.         }
  56.          public void run(){
  57.                  
  58.                  while(true){
  59.                          if(!r.flag){
  60.                                  try
  61.                                  {
  62.                                         r.wait();
  63.                                  }
  64.                                  catch (Exception e)
  65.                                  {
  66.                                          e.printStackTrace();
  67.                                  }}
  68.                                  
  69.                          synchronized(r){
  70.                      System.out.println(r.name+"::"+r.sex);
  71.                          r.flag=false;
  72.                          r.notify();
  73.                  }
  74.                   
  75.                  }
  76.           
  77.          }
  78. }

  79. //定义资源类
  80. class resource
  81. {
  82.          String name;
  83.          String sex;
  84.          boolean flag=false;

  85. }
复制代码


最佳答案

查看完整内容

首先,定义同步代码块的位置就不对,因为多线程操作共有数据时,要避免安全隐患,就需要对操作共用数据的部分进行同步, 而楼主的程序有定义标记flag,它是资源resource里的共有数据,也就是说,flag也是要放在同步代码快中。 其次, wait(): notify(); notifyAll(); 以上都使用在同步中,因为要对持有监视器(锁)的线程操作。 所以要使用在同步中,因为只有同步才具有锁。 简单点说,就是wait,notify,要放在同步代码块中才会起效 ...

11 个回复

倒序浏览
首先,定义同步代码块的位置就不对,因为多线程操作共有数据时,要避免安全隐患,就需要对操作共用数据的部分进行同步,
而楼主的程序有定义标记flag,它是资源resource里的共有数据,也就是说,flag也是要放在同步代码快中。
其次,
wait():
notify();
notifyAll();
以上都使用在同步中,因为要对持有监视器(锁)的线程操作。
所以要使用在同步中,因为只有同步才具有锁。
简单点说,就是wait,notify,要放在同步代码块中才会起效,才会有意义。

下面是修改后的代码:
  1. package justForTest;

  2. public class ThreadAccess { // 两个线程同时访问一个资源
  3.         public static void main(String[] args) {
  4.                 resource r = new resource();
  5.                 new Thread(new Input(r)).start();
  6.                 new Thread(new Output(r)).start();
  7.         }
  8. }

  9. // 存入资源线程
  10. class Input implements Runnable {
  11.         private resource r;

  12.         Input(resource r) {
  13.                 this.r = r;
  14.         }

  15.         public void run() {
  16.                 int i = 0;

  17.                 while (true) {
  18.                         synchronized (r) {                //把同步代码块放到这里来。
  19.                                 if (r.flag) {
  20.                                         try {
  21.                                                 r.wait();        //wait()使线程等待的同时,还会把锁释放。
  22.                                         } catch (Exception e) {
  23.                                                 e.printStackTrace();
  24.                                         }
  25.                                 }

  26.                                 if (i == 0) {
  27.                                         r.name = "liuliu";
  28.                                         r.sex = "nan";
  29.                                 } else {
  30.                                         r.name = "yanyan";
  31.                                         r.sex = "lv";
  32.                                 }
  33.                                 i = (1 + i) % 2;
  34.                                 r.flag = true;
  35. //                                如果是多个input线程,这里就需要改成notifyAll,
  36. //                                因为单独的notify()可能唤醒的是其他input线程,导致程序停止。
  37.                                 r.notify();
  38.                         }
  39.                 }
  40.         }
  41. }

  42. // 取出资源线程
  43. class Output implements Runnable {
  44.         private resource r;

  45.         Output(resource r) {
  46.                 this.r = r;
  47.         }

  48.         public void run() {

  49.                 while (true) {
  50.                         synchronized (r) {                //把同步代码块放到这里来。
  51.                                 if (!r.flag) {
  52.                                         try {
  53.                                                 r.wait();        //wait()使线程等待的同时,还会把锁释放。
  54.                                         } catch (Exception e) {
  55.                                                 e.printStackTrace();
  56.                                         }
  57.                                 }

  58.                                 System.out.println(r.name + "::" + r.sex);
  59.                                 r.flag = false;
  60. //                                如果是多个output线程,这里就需要改成notifyAll,
  61. //                                因为单独的notify()可能唤醒的是其他output线程,导致程序停止。
  62.                                 r.notify();
  63.                         }
  64.                 }
  65.         }
  66. }

  67. // 定义资源类
  68. class resource {
  69.         String name;
  70.         String sex;
  71.         boolean flag = false;
  72. }
复制代码


回复 使用道具 举报
为什么运行会报错··!


yanyan::lv
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at justForTest.input.run(threadAccess.java:28)
        at java.lang.Thread.run(Thread.java:745)
java.lang.IllegalMonitorStateException
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at justForTest.output.run(threadAccess.java:66)
        at java.lang.Thread.run(Thread.java:745)
java.lang.IllegalMonitorStateException
        at java.lang.Object.wait(Native Method)
liuliu::nan
        at java.lang.Object.wait(Object.java:502)
        at justForTest.input.run(threadAccess.java:28)
        at java.lang.Thread.run(Thread.java:745)
java.lang.IllegalMonitorStateException
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at justForTest.output.run(threadAccess.java:66)
        at java.lang.Thread.run(Thread.java:745)
java.lang.IllegalMonitorStateException
yanyan::lv
        at java.lang.Object.wait(Native Method)
······




回复 使用道具 举报
wait()在 放在了同步代码块外面
回复 使用道具 举报
多线程访问统一资源会产生线程死锁的问题,需要考虑线程锁的问题,同一资源必须同时由一个线程锁定
回复 使用道具 举报
嗯嗯! 楼上说的对 synchronized语句写的位置问题
回复 使用道具 举报
醉翁之意不在酒 来自手机 中级黑马 2015-7-30 00:25:48
7#
wait的位置不对,同步锁对象调用wait方法后,退出同步代码区,释放同步锁。其他的线程可以进去同步区,直到notify唤醒被阻塞的线程
你的程序注释都没有
回复 使用道具 举报
应该对同一资源进行同步代码块处理
回复 使用道具 举报
  1. package cn.itcast.itscores;

  2.         public class ThAccess {
  3.                 //两个线程同时访问一个资源
  4.                 public static void main(String[] args)
  5.                 {
  6.                 resource r=new resource();
  7.                         new Thread(new input(r)).start();
  8.                         new Thread(new output(r)).start();
  9.                 }
  10.         }

  11.         //存入资源线程
  12.         class input implements Runnable
  13.         {
  14.                 private resource r;
  15.                 input(resource r){
  16.                  this.r=r;
  17.                 }
  18.                  public void run(){
  19.                          int i=0;
  20.                          
  21.                          synchronized(r){
  22.                          while(true){
  23.                                  if(r.flag){
  24.                                          try
  25.                                          {
  26.                                                 r.wait();
  27.                                          }
  28.                                          catch (Exception e)
  29.                                          {
  30.                                                  e.printStackTrace();
  31.                                          }
  32.                                  }

  33.                          if(i==0){
  34.                                  r.name="lulu";
  35.                                  r.sex="male";
  36.                          }
  37.                          else{
  38.                            r.name="yanyan";
  39.                            r.sex="female";
  40.                          }
  41.                  i=(1+i)%2;
  42.                          r.flag=true;
  43.                          r.notify();
  44.                }
  45.                    }
  46.                   
  47.                  }
  48.         }
  49.         //取出资源线程
  50.         class output implements Runnable
  51.         {
  52.                 private resource r;
  53.                 output(resource r){
  54.                  this.r=r;
  55.                 }
  56.                  public void run(){
  57.                          
  58.                          while(true){
  59.                                  synchronized(r){
  60.                                  if(!r.flag){
  61.                                          try
  62.                                          {
  63.                                                 r.wait();
  64.                                          }
  65.                                          catch (Exception e)
  66.                                          {
  67.                                                  e.printStackTrace();
  68.                                          }}
  69.                                         
  70.                              System.out.println(r.name+"::"+r.sex);
  71.                                  r.flag=false;
  72.                                  r.notify();
  73.                          }
  74.                            
  75.                          }
  76.                   
  77.                  }
  78.         }

  79.         //定义资源类
  80.         class resource
  81.         {
  82.                  String name;
  83.                  String sex;
  84.                  boolean flag = false;

  85.         }


复制代码

如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
回复 使用道具 举报
共享数据必须都放在同步代码块中.
回复 使用道具 举报
wait()的位置不对
回复 使用道具 举报
当前线程必是锁的持有者,不然会有异常
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马