2011-10-24 193 views
3

我正在尝试编写一个邮件实用程序,它将邮件放置在一个队列中,并且之后被消费者线程使用。实现生产者消费者模式

我想实现一个典型的生产者 - 消费者模式,但出了问题。

我刚刚写了一个骷髅,骨架没有按预期工作。

MailProducer.java

public class MailProducer implements Callable<Void> 
{ 

@Override 
public Void call() throws Exception 
{ 
    System.out.println("inside mail Producer"); 
    System.out.println("Thread executing = " + 
          Thread.currentThread().getName()); 
    return null; 
} 

} 

MailConsumer.java

public class MailConsumer implements Callable<Void> 
{ 

@Override 
public Void call() throws Exception 
{ 
    System.out.println("inside mail consumer"); 
    System.out.println("Thread executing = " + 
         Thread.currentThread().getName()); 
    return null; 
} 

} 

最后执行人

MailExecutor.java

public class MailExecutor 
    { 

private static final int NTHREADS = 25; 
private static final ExecutorService exec = 
       Executors.newFixedThreadPool(NTHREADS); 

public static void main(String[] args) 
{ 
    exec.submit(new MailConsumer()); 
    exec.submit(new MailProducer()); 

    System.out.println("inside main"); 

} 

    } 

现在,当我运行该程序时,我期望它来回生产者和消费者继续打印在各个类别中编写的内容。但是,相反,程序在打印下面的行后挂起/不执行任何操作。出了什么问题?我错过了什么吗?

输出 ...(输出是不是我的预料。这是怎么回事了?)

inside mail consumer 
    inside main 
    Thread executing = pool-1-thread-1 
    inside mail Producer 
    Thread executing = pool-1-thread-2 

回答

2

您缺少共享队列。没有队列,你什么都没有。

生产者将工作放到队列中。消费者不在队列中工作。使用BlockingQueue,其put()take()方法是阻止调用。在独立的线程中运行生产者和消费者允许他们在调用这些方法时安全地阻塞。

生产者和消费者都不需要是Callable; Runnable会做。使用Executor将它们结合在一起是一个好主意。

+0

没什么大不了的,但是阻塞方法实际上是put()和take()。如果没有空间,优惠将返回false。 – devo

+0

@ user529734相当如此! thx - 已更正。 – Bohemian

1

ExecutorService.submit安排一个Runnable或赎回的一个执行。您的输出显示MailProducer和MailConsumer都执行过一次,因此所有操作都应如此。

你应该放在循环的生产者和消费者方法里面:

import java.util.concurrent.*; 

public class Executor { 

    private static final int NTHREADS = 25; 
    private static final ExecutorService exec = 
     Executors.newFixedThreadPool(NTHREADS); 


    public static void main(String[] args) { 
     exec.submit(new MailConsumer()); 
     exec.submit(new MailProducer()); 

     System.out.println("inside main"); 
    } 


    static class MailProducer implements Runnable { 
     @Override 
     public void run() { 
      while (true) { 
       System.out.println("inside mail Producer"); 
       System.out.println("Thread executing = " + 
         Thread.currentThread().getName()); 
      } 
     } 
    } 

    static class MailConsumer implements Runnable { 
     @Override 
     public void run() { 
      while (true) { 
       System.out.println("inside mail Consumer"); 
       System.out.println("Thread executing = " + 
         Thread.currentThread().getName()); 
      } 
     } 
    } 
} 

这给了你所期望的输出。

+0

尽管您的答案解决了一个重要问题,但您错过了一个重点:使用BlockingQueue或类似的东西。 – michael667

+0

是的,但原始海报的代码也是如此 - 他将其描述为骨架,所以我认为他会尝试使ThreadPool首先工作,然后再实施Producent-Consumer。 – socha23

+0

是的,但是这只会使用两个线程,并且不需要执行程序。 –

0
  1. 您必须使用循环,以便您的生产者/消费者代码被多次执行。

  2. 您的线程不会相互通信。目前你只有两个正在执行的线程。看看BlockingQueue javadoc中如何做的例子。