単一プロデューサーの単一消費者今、複数の消費者が必要

私は、シンプルなプロデューサーコンシューマーモデルを書いて、Bluetoothからデータを読み込み、10kバイトごとにファイルに書き込む状況を持っています。メッセージホルダーとしてVectorを使用した標準的なP-Cモデルを使用しました。だから私はこれを変更して複数のスレッドコンシューマが同じメッセージを読むことができるようにするにはどうすればよいでしょうか?私は実際にAndroidの携帯電話でこれを使用しているので、JMSはおそらくオプションではありません。

static final int MAXQUEUE = 50000; 
private Vector messages = new Vector(); 

/**
 * Put the message in the queue for the Consumer Thread
 */
private synchronized void putMessage(byte[] send) throws InterruptedException { 

    while ( messages.size() == MAXQUEUE ) 
        wait(); 
    messages.addElement( send ); 
    notify(); 
} 


/**
 * This method is called by the consumer to see if any messages in the queue
 */
public synchronized byte[] getMessage()throws InterruptedException { 
    notify(); 
    while ( messages.size() == 0 && !Thread.interrupted()) {
        wait(1); 
    }
    byte[] message = messages.firstElement(); 
    messages.removeElement( message ); 
    return message; 
} 

私はOreillyブックメッセージパーサーセクションのコードを参照しています

1

3 答え

Pub-Subメカニズムは間違いなくあなたが望むものを達成する方法です。 Android用に開発することでJMSの使用が制限される理由はわかりませんが、これは単純な仕様です。チェックアウト SO上のこのスレッド

1
追加された
はい、しかしそれは主に、スレッド間でメッセージを送信する電話アプリで必要なもののために一種の方法であるJMSの使用について話しています。
追加された 著者 JPM,
その場合、Observer/ObservableパターンにあなたのVector(またはHanno Binderとして提案されたQueue)を単純にラッピングすることはできますか?
追加された 著者 mazaneicha,

Vector の代わりにキューを使用してください。 code>!
すべてのスレッドに独自のキューを与え、新しいメッセージが受信されたら、新しいメッセージをすべてのスレッドのキューに追加します( add )。フレキシビリティのために、リスナーパターンも便利です。

編集:

はい、私は例を追加すべきだと感じています:
(古典的なオブザーバーパターン)

これはインタフェースであり、すべてのコンシューマが実装する必要があります。

public interface MessageListener {
  public void newMessage( byte[] message );
}

プロデューサーは次のようになります。

public class Producer {
  Collection listeners = new ArrayList();


 //Allow interested parties to register for new messages
  public void addListener( MessageListener listener ) {
    this.listeners.add( listener );
  }

  public void removeListener( Object listener ) {
    this.listeners.remove( listener );
  }

  protected void produceMessages() {
    byte[] msg = new byte[10];

   //Create message and put into msg

   //Tell all registered listeners about the new message:
    for ( MessageListener l : this.listeners ) {
      l.newMessage( msg );
    }

  }
}

コンシューマクラスは( wait()し、 notify()するすべての処理を行うブロッキングキューを使用します)。

public class Consumer implements MessageListener {

  BlockingQueue< byte[] > queue = new LinkedBlockingQueue< byte[] >();

 //This implements the MessageListener interface:
  @Override
  public void newMessage( byte[] message ) {
    try {
      queue.put( message );
    } catch (InterruptedException e) {
       //won't happen.
    }
  }

   //Execute in another thread:       
    protected void handleMessages() throws InterruptedException {
        while ( true ) {
            byte[] newMessage = queue.take();

           //handle the new message.
        }
    }


}
0
追加された
VectorとQueueの両方でオブジェクトを保持することはできますが、プリムティブは保持できません。ブロッキングキューと上記のコード全体を使用すると、queue.put(message)とqueue.take()のように簡単になります。
追加された 著者 JimmyB,
SettableFutureを動作させることができないので、私はあなたのサンプルにもっと傾いています。
追加された 著者 JPM,
私はいつもリスナーがJMSシステムからリアルタイムデータを取り出し、これらの状態変更でカスタムコンポーネントを更新するためのGUI状態リスナーシステム全体を書いたこのようなものを扱っていました。
追加された 著者 JPM,

これは、いくつかのコードを掘り下げ、いくつかの既存の例を修正する際の例として私が思いついたものです。

package test.messaging;

import java.util.ArrayList;
import java.util.concurrent.LinkedBlockingQueue;

public class TestProducerConsumers {

    static Broker broker;

    public TestProducerConsumers(int maxSize) {
        broker = new Broker(maxSize);
        Producer p = new Producer();
        Consumer c1 = new Consumer("One");
        broker.consumers.add(c1);
        c1.start();

        Consumer c2 = new Consumer("Two");
        broker.consumers.add(c2);
        c2.start();

        p.start();
    }

   //Test Producer, use your own message producer on a thread to call up
   //broker.insert() possibly passing it the message instead.
    class Producer extends Thread {

        @Override
        public void run() {
            while (true) {
                try {
                    broker.insert();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Consumer extends Thread {
        String myName;
        LinkedBlockingQueue queue;

        Consumer(String m) {
            this.myName = m;
            queue = new LinkedBlockingQueue();
        }

        @Override
        public void run() {
            while(!Thread.interrupted()) {
                try {
                    while (queue.size() == 0 && !Thread.interrupted()) {
                        ;
                    }
                    while (queue.peek() == null && !Thread.interrupted()) {
                        ;
                    }
                    System.out.println("" + myName + " Consumer: " + queue.poll());
                } catch (Exception e) { }
            }
        }
    }

    class Broker {
        public ArrayList consumers = new ArrayList();

        int n;
        int maxSize;

        public Broker(int maxSize) {
            n = 0;
            this.maxSize = maxSize;
        }

        synchronized void insert() throws InterruptedException {
                   //only here for testing don't want it to runaway and 
                    //memory leak, only testing first 100 samples.
            if (n == maxSize)
                wait();
            System.out.println("Producer: " + n++);
            for (Consumer c : consumers) {
                c.queue.add("Message " + n);
            }
        }

    }

    public static void main(String[] args) {
        TestProducerConsumers pc = new TestProducerConsumers(100);

    }
}
0
追加された
ビジー状態のために消費者の while(...)ループを使用しないでください!それは本当に悪いコーディングです。 挿入()待機()を含むブロックキューによってすべての処理が処理されます。 (とにかく対応する notify()コールはどこにありますか?)
追加された 著者 JimmyB,
それでは、 "if(n == maxSize)wait();"とは何ですか?
追加された 著者 JimmyB,
コンシューマーがwait()を使用していないため、挿入時に通知する必要はありません。 'whileはテストのために存在します。私のメッセージがリアルタイムである必要はないので、私は消費者の待ち時間の代わりにいくつかの睡眠を投げた。
追加された 著者 JPM,
もう一度100個のメッセージしかテストしない
追加された 著者 JPM,