2011-10-24 190 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中如何做的例子。