将处理过的消息发送到特定线程

时间:2011-08-04 04:17:34

标签: java multithreading

我有一组线程,每个线程必须等待其所需的输入,进行一些计算,最后将其输出值发送到特定的线程。

我计划拥有包含线程名称和线程本身的全局映射,以便让每个线程按名称获取其“后继”线程,然后向它们发送值。

首先,我使用阻塞队列查看了Producer-Consumer示例:

class Consumer implements Runnable {
    private final BlockingQueue queue;

    Consumer(BlockingQueue q) {
        queue = q;
    }

    public void run() {
        try {
            while(true) { 
                System.out.println("Waiting for input");
                consume(queue.take()); 
            }
        } catch (InterruptedException ex) { 
            ex.printStackTrace();
        }
    }

    void consume(Object x) { 
        System.out.println("Received: " + x);
    }
}

class Setup {
    public static void main(String...args) {
        BlockingQueue q = new ArrayBlockingQueue<String>(10);
        Producer p = new Producer(q);
        Consumer c1 = new Consumer(q);
        Consumer c2 = new Consumer(q);
        new Thread(p).start();
        new Thread(c1).start();
        new Thread(c2).start();
    }
}

我以为每个线程都可以有一个阻塞队列。然后,Consumer线程将循环遍历queue.take(),直到它收到所有需要的值。

后来,我找到了post,其中有一个与我类似的问题。提出的解决方案似乎比阻塞队列解决方案更容易:它基于在我想要的线程上调用方法,因此将消息发送到。

我想问你一些建议(因为我认为这是一种常见的情况)两种方法中哪种方法最好,或者有更好的方法来实现我想要的。

非常感谢你的帮助。

1 个答案:

答案 0 :(得分:2)

消费者 - 生产者很好。 (你在参考文献中提到的那个“答案”问题是一堆蠕虫......想一想......)

您可以使用QueuePipe,甚至PipedInputStreamPipedOutputStream。还有Exchanger

以下是Exchanger javadoc示例的mod。不要担心嵌套类,它只是一种紧凑的风格 - 与主题无关。

这里我们有一个'管道'类。它有2个线程(名称中的R / L指左,右)。管道流量为R-> L。

/* 
 * mostly based on 
 * http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Exchanger.html 
 */
package so_6936111;

import java.util.concurrent.Exchanger;

public class WorkflowDemo {

    public static void main(String[] args) {
        Pipeline pipeline = new Pipeline();
        pipeline.start();
    }
    // ----------------------------------------------------------------
    // Pipeline
    // ----------------------------------------------------------------

    public static class Pipeline {

        /** exchanger for messages */
        Exchanger<Message> exchanger = new Exchanger<Message>();

        /* the two message instances that are passed back and forth */
        Message msg_1 = new Message();
        Message msg_2 = new Message();

        /** startups the pipeline */
        void start() {
            new Thread(new WorkerR()).start();
            new Thread(new WorkerL()).start();
        }


        /** Message objects are passed between workflow threads */
        public static class Message {
            private Object content;
            public Object getContent() { return content; }
            public void setContent(Object c) { this.content = c; }
        }


        /** WorkerR is at the head of the pipeline */
        class WorkerR implements Runnable {
            public void run() {
                Message message = msg_1;
                try {
                    while (true) {
                        Object data = doSomeWork();
                        message.setContent(data);
                        message = exchanger.exchange(message);
                    }
                } catch (InterruptedException ex) { ex.printStackTrace();}
            }
            /** 
             * let's pretend this is where you get your 
             * initial data and do some work
             */
             private Object doSomeWork() {
                return String.format("STEP-1@t:%d", System.nanoTime());
             }
        }

        /** WorkerL is at the tail of the pipeline */
        class WorkerL implements Runnable {
            public void run() {
                Message message = msg_2;
                try {
                    while (true) {
                        message = exchanger.exchange(message);
                        Object data = doPostProcessing(message.getContent());
                        System.out.format("%s\n", data);
                    }
                } catch (InterruptedException ex) { ex.printStackTrace();}
            }

            /**
             * Let's pretend this is where the 2nd step of the workflow.
             */
            private Object doPostProcessing(Object data) {
                return String.format("%s | STEP-2@t:%d", data, System.nanoTime());
            }
        }
    }
}

输出:

STEP-1@t:1312434325594730000 | STEP-2@t:1312434325594747000
STEP-1@t:1312434325594750000 | STEP-2@t:1312434325594765000
STEP-1@t:1312434325594768000 | STEP-2@t:1312434325594784000
STEP-1@t:1312434325594787000 | STEP-2@t:1312434325594804000
STEP-1@t:1312434325594806000 | STEP-2@t:1312434325594823000
STEP-1@t:1312434325594826000 | STEP-2@t:1312434325594841000
...