黑马程序员技术交流社区

标题: 请问我这个多生产多消费究竟哪里粗了问题?!竟然死锁! [打印本页]

作者: librazeng    时间: 2013-5-15 22:47
标题: 请问我这个多生产多消费究竟哪里粗了问题?!竟然死锁!
本帖最后由 librazeng 于 2013-5-17 13:30 编辑

//资源类
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumer {
        /**生产者,消费者资源
         * @param args
         */
        private String[] items=new String[100];
        int count=0;
        int putptr=0;
        int takeptr=0;
        Lock lock=new ReentrantLock();//显示锁
        Condition con_pro=lock.newCondition();//获取两组锁的监视器
        Condition con_con=lock.newCondition();
        
        public void set(String name){
                lock.lock();
                try{
                        while(count==items.length)
                                try{con_pro.await();}catch(InterruptedException e){}
                        items[putptr]=name+ count++;
                        if(++putptr==items.length) putptr=0;
                        System.out.println(Thread.currentThread().getName()+"。。生产者。。"+items[putptr-1]);//这里究竟怎么打印才好啊?
                                con_con.signal();
                        }finally{
                                lock.unlock();
                        }
        }
        public void out(){
                lock.lock();
                try{
                        while(count==0)
                                try{con_con.await();}catch(InterruptedException e){}
                                String name=items[takeptr];
                                if(++takeptr==items.length) takeptr=0;
                                --count;
                                System.out.println(Thread.currentThread().getName()+"。。消费者。。"+name);
                                con_pro.signal();
                }finally{
                        lock.unlock();
                }
        }
}

//生产者类
class Producer implements Runnable {

        /**生产者
         * @param args
         */
        private ProducerConsumer r;
        Producer(ProducerConsumer r){
                this.r=r;
        }
        @Override
        public void run() {
                while(true){
                        r.set("烤鸭");
                }
        }
}

//消费者类
class Consumer implements Runnable{

        /**消费者
         * @param args
         */
private ProducerConsumer r;
Consumer(ProducerConsumer r){
        this.r=r;
    }
@Override
public void run() {
        r.out();
    }
}


//主函数类
public class ProducerConsumerDemo {

        /**生产者消费者主程序
         * @param args
         */
        public static void main(String[] args) {
                ProducerConsumer r=new ProducerConsumer();
                Producer p=new Producer(r);
                Consumer c=new Consumer(r);
                Thread t0=new Thread(p);
                Thread t1=new Thread(p);
                Thread t2=new Thread(c);
                Thread t3=new Thread(c);
                t0.start();
                t1.start();
                t2.start();
                t3.start();
        }
}
输出结果竟然有死锁和数组角标越界发生,求解释,谢谢!

作者: 萌小子    时间: 2013-5-16 00:21
本帖最后由 王盟盟 于 2013-5-16 00:58 编辑

你这个就是API中的例子么
if(++putptr==items.length) putptr=0;
                        System.out.println(Thread.currentThread().getName()+"。。生产者。。"+items[putptr-1]);//这里是数组越界的问题所在,你把putptr赋值为0了,items[putptr-1]自然就越界了
死锁的问题我调试了半天也没解决,等高手吧
作者: librazeng    时间: 2013-5-16 00:57
王盟盟 发表于 2013-5-16 00:21
if(++putptr==items.length) putptr=0;
                        System.out.println(Thread.currentThread ...

谢谢!我把那几行调整如下:
        items[putptr]=name+ count++;
        System.out.println(Thread.currentThread().getName()+"。。生产者。。"+items[putptr]);
        if(++putptr==items.length) putptr=0;
输出结果:
Thread-1。。生产者。。烤鸭98
Thread-1。。生产者。。烤鸭99
Thread-3。。消费者。。烤鸭1
Thread-2。。消费者。。烤鸭2
Thread-0。。生产者。。烤鸭98
Thread-0。。生产者。。烤鸭99
输出停止,线程未停止,请问这又是为什么?
作者: 萌小子    时间: 2013-5-16 01:00
本帖最后由 王盟盟 于 2013-5-16 01:01 编辑
librazeng 发表于 2013-5-16 00:57
谢谢!我把那几行调整如下:
        items=name+ count++;
        System.out.println(Thread.currentThread().getNam ...


这就是死锁了,问题出在哪,我也没弄清楚  等高手吧。我的建议是改为
if(putptr==items.length-1)
           putptr=0;
System.out.println(Thread.currentThread().getName()+"。。生产者。。"+items[putptr]);//这样会不会更容易理解点



作者: 黑马伍哲沂    时间: 2013-5-16 10:52
瞎忙活了一阵。        发现错误所在的时候。  我只能说很无奈。

一直以为是让线程等待的条件设置有问题。

第一,角标越界是因为,System.out.println(Thread.currentThread().getName() + "。。生产者。。" + items[putptr-1]);//这里-1,去掉改成items[putptr].
第二个问题,这里不叫死锁。死锁的基本条件是同步中嵌套同步。这里并不符合。程序挂着的原因应该是一部分线程在等待,另外一部分线程在锁外面进不来。   
贴一小段代码,你仔细看看和你的程序的不同之处。然后就知道程序问题出在哪了。其实很简单。
  1. // 生产者类
  2. class Producer implements Runnable
  3. {
  4.         private ProducerConsumer r;
  5.         Producer(ProducerConsumer r)
  6.         {
  7.                 this.r = r;
  8.         }
  9.         @Override public void run()
  10.         {
  11.                 while (true)
  12.                 {
  13.                         r.set("烤鸭");
  14.                 }
  15.         }
  16. }
  17. // 消费者类
  18. class Consumer implements Runnable
  19. {
  20.         private ProducerConsumer r;
  21.         Consumer(ProducerConsumer r)
  22.         {
  23.                 this.r = r;
  24.         }
  25.         @Override public void run()
  26.         {
  27.                 while (true)
  28.                 {
  29.                         r.out();
  30.                 }
  31.         }
  32. }
复制代码

作者: librazeng    时间: 2013-5-16 16:33
黑马伍哲沂 发表于 2013-5-16 10:52
瞎忙活了一阵。        发现错误所在的时候。  我只能说很无奈。

一直以为是让线程等待的条件设置有问题。 ...

你也没搞清楚吧。理想的结果是生产者和消费者交替输出,不断循环。
Thread-3。。消费者。。烤鸭1
Thread-2。。消费者。。烤鸭2
Thread-0。。生产者。。烤鸭98
Thread-0。。生产者。。烤鸭99
出现这种结果,我不能完全解释。我只知道最后的烤鸭98、烤鸭99并不是重新生产的,而是items[0]和items[1]指向了已经存储在数组中的烤鸭98,烤鸭99.但在这之后,消费者为什么没有继续消费呢?
作者: 黑马伍哲沂    时间: 2013-5-16 18:51
librazeng 发表于 2013-5-16 16:33
你也没搞清楚吧。理想的结果是生产者和消费者交替输出,不断循环。
Thread-3。。消费者。。烤鸭1
Thread- ...

我多次运行后 没有出现过你说的这种情况。

我的理解是  你这里每生产100个,就消费100个。这样交替输出。

如果你是想生产一个,消费一个。  那就要修改很多地方了。
作者: librazeng    时间: 2013-5-16 18:56
黑马伍哲沂 发表于 2013-5-16 18:51
我多次运行后 没有出现过你说的这种情况。

我的理解是  你这里每生产100个,就消费100个。这样交替输出 ...

哦?那你的运行结果是怎么样的?我这里总是莫名其妙的停掉。
多生产和多消费,我觉得理想的情况是:生产者只管生产,只要没有100只就继续生产;消费者只管消费,只要还有就继续消费。生产和消费都是多条线程同时运行,随机切换的,永续进行的。
作者: 黑马伍哲沂    时间: 2013-5-16 20:04
librazeng 发表于 2013-5-16 18:56
哦?那你的运行结果是怎么样的?我这里总是莫名其妙的停掉。
多生产和多消费,我觉得理想的情况是:生产 ...

貌似就是这样的啊。。

QQ图片20130516200336.jpg (97.67 KB, 下载次数: 0)

QQ图片20130516200336.jpg

作者: 殇_心。    时间: 2013-5-16 20:30
如果问题已解决,请及时修改分类,否则继续提问,谢谢合作!
作者: librazeng    时间: 2013-5-16 23:05
黑马伍哲沂 发表于 2013-5-16 20:04
貌似就是这样的啊。。

更神奇了,我这里全是这样。
资源:
  1. public class ProducerConsumer {

  2.         /**生产者,消费者资源
  3.          * @param args
  4.          */
  5.         private String[] items=new String[100];
  6.         int count=0;
  7.         int putptr=0;
  8.         int takeptr=0;
  9.         Lock lock=new ReentrantLock();//显示锁
  10.         Condition con_pro=lock.newCondition();//获取2组锁的监视器
  11.         Condition con_con=lock.newCondition();
  12.        
  13.         public void set(String name){
  14.                 lock.lock();
  15.                 try{
  16.                                 while(count==items.length)
  17.                                         try{con_pro.await();}catch(InterruptedException e){}//线程阻塞,放弃了锁
  18.                                 items[putptr]=name+ ++count;
  19.                                 System.out.println(Thread.currentThread().getName()+"。。生产者。。"+items[putptr]);//
  20.                                 if(++putptr==items.length)
  21.                                         putptr=0;
  22.                                 con_con.signal();
  23.                         }finally{
  24.                                 lock.unlock();
  25.                         }
  26.         }
  27.         public void out(){
  28.                 lock.lock();
  29.                 try{
  30.                                 while(count==0)
  31.                                         try{con_con.await();}catch(InterruptedException e){}//线程阻塞,放弃了锁
  32.                                 String name=items[takeptr];
  33.                                 if(++takeptr==items.length)
  34.                                         takeptr=0;
  35.                                 --count;
  36.                                 System.out.println(Thread.currentThread().getName()+"。。消费者。。"+name);
  37.                                 con_pro.signal();
  38.                 }finally{
  39.                         lock.unlock();
  40.                 }
  41.         }
  42. }
复制代码
结果:
Thread-1。。生产者。。烤鸭98
Thread-1。。生产者。。烤鸭99
Thread-1。。生产者。。烤鸭100
Thread-2。。消费者。。烤鸭1
Thread-3。。消费者。。烤鸭2
Thread-0。。生产者。。烤鸭99
Thread-0。。生产者。。烤鸭100
输出停止....
作者: 黑马伍哲沂    时间: 2013-5-17 07:28
librazeng 发表于 2013-5-16 23:05
更神奇了,我这里全是这样。
资源:结果:
Thread-1。。生产者。。烤鸭98

我之前提供的代码段里 增加了一个while啊,估计你没看到。。。。
作者: librazeng    时间: 2013-5-17 10:05
本帖最后由 librazeng 于 2013-5-17 13:31 编辑
黑马伍哲沂 发表于 2013-5-17 07:28
我之前提供的代码段里 增加了一个while啊,估计你没看到。。。。

我的代码里增加了那个while(ture)啊,还是那样。。我觉得问题出在count满100之后的运行上。
  1. import java.util.concurrent.locks.Condition;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;

  4. public class ProducerConsumer {

  5.         /**生产者,消费者资源
  6.          * @param args
  7.          */
  8.         private String[] items=new String[100];
  9.         int count=0;
  10.         int putptr=0;
  11.         int takeptr=0;
  12.         Lock lock=new ReentrantLock();//显示锁
  13.         Condition con_pro=lock.newCondition();//获取2组锁的监视器
  14.         Condition con_con=lock.newCondition();
  15.         
  16.         public void set(String name){
  17.                 lock.lock();
  18.                 try{
  19.                                 while(count==items.length)
  20.                                         try{con_pro.await();}catch(InterruptedException e){}//线程阻塞,放弃了锁
  21.                                 items[putptr]=name+ ++count;
  22.                                 System.out.println(Thread.currentThread().getName()+"。。生产者。。"+items[putptr]);//
  23.                                 if(++putptr==items.length)
  24.                                         putptr=0;
  25.                                 con_con.signal();
  26.                         }finally{
  27.                                 lock.unlock();
  28.                         }
  29.         }
  30.         public void out(){
  31.                 lock.lock();
  32.                 try{
  33.                                 while(count==0)
  34.                                         try{con_con.await();}catch(InterruptedException e){}//线程阻塞,放弃了锁
  35.                                 String name=items[takeptr];
  36.                                 if(++takeptr==items.length)
  37.                                         takeptr=0;
  38.                                 --count;
  39.                                 System.out.println(Thread.currentThread().getName()+"。。消费者。。"+name);
  40.                                 con_pro.signal();
  41.                 }finally{
  42.                         lock.unlock();
  43.                 }
  44.         }
  45. }


  46. class Producer implements Runnable {

  47.         /**生产者
  48.          * @param args
  49.          */
  50.         private ProducerConsumer r;
  51.         Producer(ProducerConsumer r){
  52.                 this.r=r;
  53.         }
  54.         @Override
  55.         public void run() {
  56.                 while(true){
  57.                         r.set("烤鸭");
  58.                 }
  59.         }
  60. }


  61. public class Output implements Runnable{<font color="#ff0000">//尼玛的,搞错了一类,眼珠挖掉。。。</font>
  62.         ThreadResource r;
  63.         Output(ThreadResource r){
  64.                 this.r=r;
  65.         }
  66.         public void run(){
  67.                 while(true){
  68.                         r.out();
  69.                 }
  70. }
  71. }

  72. public class ProducerConsumerDemo {

  73.         /**生产者消费者主程序
  74.          * @param args
  75.          */
  76.         public static void main(String[] args) {
  77.                 ProducerConsumer r=new ProducerConsumer();
  78.                 Producer p=new Producer(r);
  79.                 Consumer c=new Consumer(r);
  80.                 Thread t0=new Thread(p);
  81.                 Thread t1=new Thread(p);
  82.                 Thread t2=new Thread(c);
  83.                 Thread t3=new Thread(c);
  84.                 t0.start();
  85.                 t1.start();
  86.                 t2.start();
  87.                 t3.start();
  88.         }
  89. }
复制代码
结果:
Thread-0。。生产者。。烤鸭1
Thread-3。。消费者。。烤鸭1
Thread-0。。生产者。。烤鸭1
Thread-0。。生产者。。烤鸭2
Thread-0。。生产者。。烤鸭3
Thread-0。。生产者。。烤鸭4
Thread-0。。生产者。。烤鸭5
Thread-0。。生产者。。烤鸭6
Thread-0。。生产者。。烤鸭7
Thread-0。。生产者。。烤鸭8
Thread-0。。生产者。。烤鸭9
Thread-0。。生产者。。烤鸭10
Thread-0。。生产者。。烤鸭11
Thread-0。。生产者。。烤鸭12
Thread-0。。生产者。。烤鸭13
Thread-0。。生产者。。烤鸭14
Thread-0。。生产者。。烤鸭15
Thread-0。。生产者。。烤鸭16
Thread-0。。生产者。。烤鸭17
Thread-0。。生产者。。烤鸭18
Thread-0。。生产者。。烤鸭19
Thread-0。。生产者。。烤鸭20
Thread-0。。生产者。。烤鸭21
Thread-0。。生产者。。烤鸭22
Thread-0。。生产者。。烤鸭23
Thread-0。。生产者。。烤鸭24
Thread-0。。生产者。。烤鸭25
Thread-0。。生产者。。烤鸭26
Thread-0。。生产者。。烤鸭27
Thread-0。。生产者。。烤鸭28
Thread-0。。生产者。。烤鸭29
Thread-0。。生产者。。烤鸭30
Thread-0。。生产者。。烤鸭31
Thread-0。。生产者。。烤鸭32
Thread-0。。生产者。。烤鸭33
Thread-0。。生产者。。烤鸭34
Thread-0。。生产者。。烤鸭35
Thread-0。。生产者。。烤鸭36
Thread-0。。生产者。。烤鸭37
Thread-0。。生产者。。烤鸭38
Thread-0。。生产者。。烤鸭39
Thread-0。。生产者。。烤鸭40
Thread-0。。生产者。。烤鸭41
Thread-0。。生产者。。烤鸭42
Thread-0。。生产者。。烤鸭43
Thread-0。。生产者。。烤鸭44
Thread-0。。生产者。。烤鸭45
Thread-0。。生产者。。烤鸭46
Thread-0。。生产者。。烤鸭47
Thread-0。。生产者。。烤鸭48
Thread-0。。生产者。。烤鸭49
Thread-0。。生产者。。烤鸭50
Thread-0。。生产者。。烤鸭51
Thread-0。。生产者。。烤鸭52
Thread-0。。生产者。。烤鸭53
Thread-0。。生产者。。烤鸭54
Thread-0。。生产者。。烤鸭55
Thread-0。。生产者。。烤鸭56
Thread-0。。生产者。。烤鸭57
Thread-0。。生产者。。烤鸭58
Thread-0。。生产者。。烤鸭59
Thread-0。。生产者。。烤鸭60
Thread-0。。生产者。。烤鸭61
Thread-0。。生产者。。烤鸭62
Thread-0。。生产者。。烤鸭63
Thread-0。。生产者。。烤鸭64
Thread-0。。生产者。。烤鸭65
Thread-0。。生产者。。烤鸭66
Thread-0。。生产者。。烤鸭67
Thread-0。。生产者。。烤鸭68
Thread-0。。生产者。。烤鸭69
Thread-0。。生产者。。烤鸭70
Thread-0。。生产者。。烤鸭71
Thread-0。。生产者。。烤鸭72
Thread-0。。生产者。。烤鸭73
Thread-0。。生产者。。烤鸭74
Thread-0。。生产者。。烤鸭75
Thread-0。。生产者。。烤鸭76
Thread-0。。生产者。。烤鸭77
Thread-0。。生产者。。烤鸭78
Thread-0。。生产者。。烤鸭79
Thread-0。。生产者。。烤鸭80
Thread-0。。生产者。。烤鸭81
Thread-0。。生产者。。烤鸭82
Thread-0。。生产者。。烤鸭83
Thread-0。。生产者。。烤鸭84
Thread-0。。生产者。。烤鸭85
Thread-0。。生产者。。烤鸭86
Thread-0。。生产者。。烤鸭87
Thread-0。。生产者。。烤鸭88
Thread-0。。生产者。。烤鸭89
Thread-0。。生产者。。烤鸭90
Thread-0。。生产者。。烤鸭91
Thread-0。。生产者。。烤鸭92
Thread-0。。生产者。。烤鸭93
Thread-0。。生产者。。烤鸭94
Thread-0。。生产者。。烤鸭95
Thread-0。。生产者。。烤鸭96
Thread-0。。生产者。。烤鸭97
Thread-0。。生产者。。烤鸭98
Thread-0。。生产者。。烤鸭99
Thread-0。。生产者。。烤鸭100
Thread-2。。消费者。。烤鸭1
Thread-0。。生产者。。烤鸭100
输出停止,线程未停。
求解释啊。。。
作者: 黑马伍哲沂    时间: 2013-5-17 11:21
librazeng 发表于 2013-5-17 10:05
我的代码里增加了那个while(ture)啊,还是那样。。我觉得问题出在count满100之后的运行上。结果:
Thread ...
  1. package com.itheima.reflect;

  2. import java.util.concurrent.locks.Condition;
  3. import java.util.concurrent.locks.Lock;
  4. import java.util.concurrent.locks.ReentrantLock;

  5. class ProducerConsumer
  6. {
  7.         private String[] items = new String[100];
  8.         int count = 0;
  9.         int putptr = 0;
  10.         int takeptr = 0;
  11.         Lock lock = new ReentrantLock();// 显示锁
  12.         Condition con_pro = lock.newCondition();// 获取两组锁的监视器
  13.         Condition con_con = lock.newCondition();

  14.         public void set(String name)
  15.         {
  16.                 lock.lock();
  17.                 try
  18.                 {
  19.                         while (count == items.length)
  20.                                 try
  21.                                 {
  22.                                         con_pro.await();
  23.                                 }
  24.                                 catch (InterruptedException e)
  25.                                 {
  26.                                 }
  27.                         items[putptr] = name + count++;
  28.                         System.out.println(Thread.currentThread().getName() + "。。生产者。。" + items[putptr]);// 这里究竟怎么打印才好啊?
  29.                         if (++putptr == items.length)
  30.                                 putptr = 0;
  31.                         con_con.signal();
  32.                 }
  33.                 finally
  34.                 {
  35.                         lock.unlock();
  36.                 }
  37.         }
  38.         public void out()
  39.         {
  40.                 lock.lock();
  41.                 try
  42.                 {
  43.                         while (count == 0)
  44.                                 try
  45.                                 {
  46.                                         con_con.await();
  47.                                 }
  48.                                 catch (InterruptedException e)
  49.                                 {
  50.                                 }
  51.                         String name = items[takeptr];
  52.                         if (++takeptr == items.length)
  53.                                 takeptr = 0;
  54.                         --count;
  55.                         System.out.println(Thread.currentThread().getName() + "。。消费者。。" + name);
  56.                         con_pro.signal();
  57.                 }
  58.                 finally
  59.                 {
  60.                         lock.unlock();
  61.                 }
  62.         }
  63. }

  64. // 生产者类
  65. class Producer implements Runnable
  66. {
  67.         private ProducerConsumer r;
  68.         Producer(ProducerConsumer r)
  69.         {
  70.                 this.r = r;
  71.         }
  72.         @Override public void run()
  73.         {
  74.                 while (true)
  75.                 {
  76.                         r.set("烤鸭");
  77.                 }
  78.         }
  79. }
  80. // 消费者类
  81. class Consumer implements Runnable
  82. {
  83.         private ProducerConsumer r;
  84.         Consumer(ProducerConsumer r)
  85.         {
  86.                 this.r = r;
  87.         }
  88.         @Override public void run()
  89.         {
  90.                 while (true)
  91.                 {
  92.                         r.out();
  93.                 }
  94.         }
  95. }

  96. // 主函数类
  97. public class ProducerConsumerDemo
  98. {
  99.         public static void main(String[] args)
  100.         {
  101.                 ProducerConsumer r = new ProducerConsumer();
  102.                 Producer p = new Producer(r);
  103.                 Consumer c = new Consumer(r);
  104.                 Thread t0 = new Thread(p);
  105.                 Thread t1 = new Thread(p);
  106.                 Thread t2 = new Thread(c);
  107.                 Thread t3 = new Thread(c);
  108.                 t0.start();
  109.                 t1.start();
  110.                 t2.start();
  111.                 t3.start();
  112.         }
  113. }
复制代码
把我代码给你看看。  你自己对照下。我的运行结果没任何问题。

QQ图片20130517111935.jpg (105.3 KB, 下载次数: 0)

QQ图片20130517111935.jpg

作者: librazeng    时间: 2013-5-17 13:27
黑马伍哲沂 发表于 2013-5-17 11:21
把我代码给你看看。  你自己对照下。我的运行结果没任何问题。

谢谢,我成功了!!!
原来我混淆了一个类。。。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2