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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© lh994749769 中级黑马   /  2014-12-7 16:34  /  1676 人查看  /  11 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

package test.first;

public class Test1 {
       

        public static void main(String[] args) {
                // TODO Auto-generated method stub
                Production p = new Production();
                new Thread(new Product(p)).start();
                new Thread(new Consumption(p)).start();

        }

}

class Production{
        public  String name;
        public  boolean isExist;
        public Production() {
                this.isExist = false;
        }
}
class Product implements Runnable{
        private Production p;
        Product(Production p){
                this.p = p;
        }
        @Override
        public void run() {
                // TODO Auto-generated method stub
                int i = 0;
                while(true){

                                if(!p.isExist){
                                        p.name = "baozi_"+i;
                                        p.isExist = true;
                                        System.out.println("生产一个"+p.name+p.isExist);
                                        i++;
                                }

       

                }
               
        }
       
}
class Consumption implements Runnable{
        private Production p;
        public Consumption(Production p) {
                // TODO Auto-generated constructor stub
                this.p = p;

        }

        @Override
        public void run() {
                // TODO Auto-generated method stub
                while(true){

                                if(p.isExist){
                                       
                                        p.isExist =false;
                                        System.out.println("消费一个:"+p.name+p.isExist);
                                }
       
                }
               
        }
}
程序目的:生产者生产一个,消费者便消费一个
理想运行结果:生产一个,消费一个
已经理解的错误:会出现连续生产3个,2个,或消费3个,2个,或者先消费再生产,原因:争夺共享资源isExist造成的
无法理解的错误:程序运行后不就会进入阻塞状态无法继续下去,控制台只出现不定量的几行运行结果
求解释啊

11 个回复

倒序浏览
仔细琢磨
回复 使用道具 举报
楼主你好。

这题的问题在于多线程的安全问题。为了保证多线程的安全,一般都会使用同步代码块或同步方法。
俗称“锁”。
以下附件是我在楼主代码基础上增加了同步代码块,请参考一下。

以下从Product的run代码中简单说明一下,若看不明白请回头再看看毕老师11天的讲课内容:

public void run() {
                // TODO Auto-generated method stub
                int i = 0;
                while(true){
                        if(p.isExist == false){
                                synchronized(this.p){-------------------------------此处的代码即为访问共用变量的同步代码块,为了保证访问唯一性而上锁
                                        p.name = "baozi_"+i;
                                        p.isExist = true;
                                        System.out.println("生产一个"+p.name+p.isExist);
                                        i++;

                        }
                }
        }

practice02.rar

594 Bytes, 下载次数: 39

回复 使用道具 举报
代码一多看起来就好迷茫
回复 使用道具 举报
旅人の影 发表于 2014-12-7 17:26
楼主你好。

这题的问题在于多线程的安全问题。为了保证多线程的安全,一般都会使用同步代码块或同步方法。 ...

这个我知道加锁,我的问题在于,在不加锁的情况下,也不应该出现只打印几行数据就不在再打印的情况啊
回复 使用道具 举报
那是因为你的p.isExist如果是true而生产者抢到CPU执行权,它就不打印生产,而在不停的执行while循环,有点像死循环;反之p.isExist是false而消费者抢到CPU执行权就是消费者里的while不停执行。就像while里面是空代码就是死循环一样了。就直接把CPU给拖死了不。    跟死循环有差别是有一方能进入if里面去打印程序还是可以执行的,在循环体里面加上sleep就可以让CPU不那么累,也就可以往下执行了。比如:
  1. public class Test1 {
  2.         public static void main(String[] args) {
  3.                 Production p = new Production();
  4.                 new Thread(new Product(p)).start();
  5.                 new Thread(new Consumption(p)).start();
  6.         }
  7. }

  8. class Production {
  9.         public String name;
  10.         public boolean isExist;

  11.         public Production() {
  12.                 this.isExist = false;
  13.         }
  14. }

  15. class Product implements Runnable {
  16.         private Production p;

  17.         Product(Production p) {
  18.                 this.p = p;
  19.         }
  20.         public void run() {
  21.                 int i = 0;
  22.                 while (true) {
  23.                         try {
  24.                                 Thread.sleep(30);
  25.                         } catch (InterruptedException e) {
  26.                                 e.printStackTrace();
  27.                         }
  28.                         if (!p.isExist) {
  29.                                 p.name = "baozi_" + i;
  30.                                 p.isExist = true;
  31.                                 System.out.println("生产一个" + p.name + p.isExist);
  32.                                 i++;
  33.                         }
  34.                 }

  35.         }

  36. }

  37. class Consumption implements Runnable {
  38.         private Production p;
  39.         public Consumption(Production p) {
  40.                 this.p = p;
  41.         }
  42.         public void run() {
  43.                 while (true) {
  44.                         try {
  45.                                 Thread.sleep(30);
  46.                         } catch (InterruptedException e) {
  47.                                 e.printStackTrace();
  48.                         }
  49.                         if (p.isExist) {
  50.                                 p.isExist = false;
  51.                                 System.out.println("消费一个:" + p.name + p.isExist);
  52.                         }
  53.                 }
  54.         }
  55. }
复制代码
回复 使用道具 举报
abathe 中级黑马 2014-12-9 09:17:34
7#
还没学习到,受教!!!!!!!!!!
回复 使用道具 举报
你得有个锁  因为cpu的随机性 可能每次都是生产分配到  你就用锁强制让他在不该他走的时候让他停住  然后把锁释放出来  让消费用了之后才让他好使   然后又开始随即抢cpu  这时候如果消费抢到 他又挂住   把锁丢出来   让生产得到
  1. import java.util.concurrent.locks.Condition;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;


  4. class Money{
  5.        
  6.         private String name;
  7.         private String sum;
  8.         private int count=1;
  9.         private int num=1;
  10.         private boolean flag = false;
  11.         private Lock lock=new ReentrantLock();
  12.         private Condition condition_set=lock.newCondition();
  13.         private Condition condition_get=lock.newCondition();
  14.         public void Set(String name)throws Exception{
  15.                 lock.lock();
  16.                 while(flag)
  17.                         condition_set.await();
  18.                 this.name=name+".."+(count++)+"美元";
  19.                 System.out.println(Thread.currentThread().getName()+"....."+this.name);
  20.                 flag=true;
  21.                 condition_get.signal();
  22.                 lock.unlock();
  23.         }
  24.         public void Get(String name)throws Exception{
  25.                 lock.lock();
  26.                 while(!flag)
  27.                         condition_get.await();
  28.                 this.sum=name+(num++)+"美元";
  29.                 System.out.println(Thread.currentThread().getName()+this.sum);
  30.                 flag=false;
  31.                 condition_set.signal();
  32.                 lock.unlock();
  33.         }
  34.        
  35. }
  36. class Set implements Runnable{
  37.          private Money money ;
  38.                
  39.                  Set(Money money){
  40.                         this.money = money;
  41.                 }
  42.         @Override
  43.         public void run() {
  44.                 // TODO Auto-generated method stub
  45.                 try {
  46.                         while(true)
  47.                         money.Set("捡钱");
  48.                 } catch (Exception e) {
  49.                         // TODO Auto-generated catch block
  50.                         e.printStackTrace();
  51.                 }
  52.                
  53.         }
  54.        
  55. }
  56. class Get implements Runnable{
  57.         private Money money;
  58.          Get(Money money){
  59.                 this.money=money;
  60.         }
  61.         public void run(){
  62.                 try {
  63.                         while(true)
  64.                         money.Get("用钱");
  65.                 } catch (Exception e) {
  66.                         // TODO Auto-generated catch block
  67.                         e.printStackTrace();
  68.                 }
  69.         }
  70. }
  71. public class SetGEetDemo {
  72.         public static void main(String[] args){
  73.                
  74.                 Money money =new Money();
  75.                 Set s = new Set(money);
  76.                 Get g = new Get(money);
  77.                 Thread t1 =new Thread(s);
  78.                 Thread t2 =new Thread(s);
  79.                 Thread t3 =new Thread(s);
  80.                 Thread t4 =new Thread(g);
  81.                 Thread t5 =new Thread(g);
  82.                 Thread t6 =new Thread(g);
  83.                 t1.start();
  84.                 t2.start();
  85.                 t3.start();
  86.                 t4.start();
  87.                 t5.start();
  88.                 t6.start();
  89.         }
  90.        
  91.        

  92. }
复制代码
回复 使用道具 举报
恩 我运行也会出现同样的问题,只出现几行代码,有时多点,有时少点。至于为什么卡主了我想是因为cpu只执行其中一个线程而忽略了另一个,而这个执行的线程因为标记是false,所以while循环体是空所以没有输出了。
回复 使用道具 举报
消费的时候使用 条件对象 可以解决
回复 使用道具 举报
fatesabering 发表于 2014-12-9 11:01
恩 我运行也会出现同样的问题,只出现几行代码,有时多点,有时少点。至于为什么卡主了我想是因为cpu只执行 ...

就你看懂了我问的是啥,我是在问,问题出在哪里,其他人都回答怎么解决~ ~!。。。。不过你这个原因也说不过去吧,cpu怎么会一直卡在一个线程上,这个原因不太可能吧,也许是多线程执行while(true){}空循环时的一些特殊机制吧,因为如果在if后加上else输出一句话(也就是不让它出现空循环的情况),那么这个程序就不会卡死
回复 使用道具 举报 1 0
lh994749769 发表于 2014-12-9 12:26
就你看懂了我问的是啥,我是在问,问题出在哪里,其他人都回答怎么解决~ ~!。。。。不过你这个原因也说 ...

恩 有道理,估计是这样
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马