【问题标题】:producer-consumer using synchronization生产者-消费者使用同步
【发布时间】:2010-12-14 18:55:42
【问题描述】:

我编写了代码来实现生产者-消费者问题,它似乎可以正常工作而无需同步。这可能吗?

我如何测试代码并检查它是否真的工作正常?我怎么知道是否会发生死锁?现在,我没有跳出循环(即生产者不断插入,消费者不断在无限循环中消费)。我使用大小为 3 的循环队列(为简单起见)作为共享资源。

这是我的代码:

import java.util.*;

public class PCImpl implements Runnable 
{
Thread t;
QforPC qObj;

 public static void main(String[] args)
 {
     QforPC qObject=new QforPC();

     //These create 2 different objects! Each object has it's own thread of execution.
     //Synchronization is needed when 2 threads use the same object
    new PCImpl("Producer",qObject);
    new PCImpl("Consumer",qObject);
 }

 PCImpl(String name,QforPC qObj)
 {
     this.qObj=qObj;
     t=new Thread(this,name);
     t.start();
 }

 public void run()
 {
         if(Thread.currentThread().getName().equals("Producer"))
         {
             while(true)
             {
                  Random rgen=new Random();
                  int n=rgen.nextInt(100);
                  if(n!=0)
                              qObj.Producer(n);
                         try
                    {
                       Thread.sleep(200);
                     }
                      catch(InterruptedException e)
                    {

                    }
               }

            }


         if(Thread.currentThread().getName().equals("Consumer"))
         {
             while(true)
                  {
                 try
               {
                 Thread.sleep(1500);
               }
                catch(InterruptedException e)
               {
                  }
              qObj.Consumer();

              }
         }

  }
}



public class QforPC 
{
int[] q={0,0,0};
int r=0,f=0;
  public void Producer(int item)
     {

         if(r!=q.length && canProducer())
         {
             q[r]=item;
             System.out.println("The item inserted into the queue is:"+ item);
             r++;
         }
         if(r==q.length && f>0)
             r=0;
         else if(r==q.length && f==q.length)
         {
             r=0;
             f=0;
         }
     }

     public void Consumer()
     {
         int item;
         System.out.println("The value of isQueue empty is:"+ isEmpty());

         if(f!=q.length && isEmpty()==false)
         {
             System.out.println("Entered the consumer method");
             item=q[f];
             System.out.println("The item fetched from the queue is:"+item);
             q[f]=0;
             f++;
         }
         if(f==q.length && r<f)
             f=0;

     }

     public boolean isEmpty()
     {
         for(int k=0;k<q.length;k++)
         {
             if(q[k]==0 && k==q.length-1)
                 return true;

         }
         return false;
     }

     public boolean canProducer()
     {
         for(int k=0;k<q.length;k++)
         {
                 if(q[k]==0)
                 return true;

         }
         return false;
     }
} 

【问题讨论】:

  • 如果你删除Sleeps,它可能会搞砸。
  • 欢迎了解计时错误的本质。在它完全爆炸之前,它似乎工作正常。
  • 为什么不把生产者和消费者的逻辑分成Runnable的两个独立实现呢?这种设计非常不雅,会导致代码完全不可维护。
  • @Mark- 这是否意味着没有同步就无法工作?另外,谢谢你的建议!
  • 可悲的是,您的助教可能不知道如何正确测试代码和/或指出问题的原因。至少如果他们和我一样的话......

标签: java synchronization producer-consumer


【解决方案1】:

您尝试做的是使用忙等待实现同步。在伪代码中,您基本上在做的是:

Producer()
{
   if (buffer.hasemptyspaces())
   {
      produce(buffer);
   }
   else
   {
      sleep(n);
   }
}

Consumer()
{
   if (buffer.hasfullspaces())
   {
      consume(buffer);
   }
   else
   {
      sleep(n);
   }
}

您的代码将正常工作,直到生产者和消费者同时尝试执行生产()和消费()。换句话说,这其中的任何一个都可能不会经常发生,但绝对有可能并且一定会发生!

在 Java 中,ConcurrentLinkedQueue 为共享缓冲区实现了无等待算法。如果您环顾四周,我相信这是其他实现。

【讨论】:

  • 那么,这意味着在我的实现中没有同步就无法工作,并且在某些时候程序会崩溃?
  • 是的。在实现线程和共享数据时,考虑“如果有一种方法可以让你的线程以一种会崩溃的方式交错,调度程序会找到它”是很有用的。
【解决方案2】:

没有the Producer-Consumer problem 这样的东西。生产者-消费者是一种设计模式,它可能是也可能不是问题解决方案的有效实现,而不是问题本身。

我确信有很多不需要同步的生产者-消费者实现。这完全取决于您要完成的工作以及您正在生产/使用的数据类型。

另外,如果你想说你的实现在没有同步的情况下工作,你必须有一个问题要解决。从事什么工作?我不知道你在做什么。

【讨论】:

  • 我只是想生产然后消费!
  • 有趣的是,维基百科上关于“生产者-消费者问题”的文章似乎不同意。
  • 看来我对问题的定义和他们的不一样。我想这就是为什么我是工程师而不是计算机科学家的原因。
【解决方案3】:

可以使用无锁队列来完成,但不是这样,我建议您阅读 Java 并发实践。如果您的代码同时被多个线程访问,您将有很多错误,您有发布和同步问题!但就像 Farlmarri 所说的,这取决于这段代码的用法。

【讨论】:

    【解决方案4】:

    您实际上并没有解决生产者/消费者问题,而只是在解决它 :) 您的代码之所以有效,是因为时间安排,并且因为如果两个线程之一未能放置/检索它要求的资源,它基本上会休眠一段时间并再次尝试。尽管这种工作(当您不必立即处理事件时)它会浪费 CPU 时间。

    这就是为什么强烈建议使用信号量来解决此类问题,您可以在此处阅读

    http://en.wikipedia.org/wiki/Producer-consumer_problem

    再见

    【讨论】:

    • 实际上,看起来 OP 的实现与那篇文章中列为“不充分”的实现非常相似。
    猜你喜欢
    • 1970-01-01
    • 2018-01-07
    • 1970-01-01
    • 2018-01-07
    • 1970-01-01
    • 1970-01-01
    • 2018-12-13
    • 1970-01-01
    • 2018-10-16
    相关资源
    最近更新 更多