我有一组线程,每个线程必须等待其所需的输入,进行一些计算,最后将其输出值发送到特定的线程。
我计划拥有包含线程名称和线程本身的全局映射,以便让每个线程按名称获取其“后继”线程,然后向它们发送值。
首先,我使用阻塞队列查看了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,其中有一个与我类似的问题。提出的解决方案似乎比阻塞队列解决方案更容易:它基于在我想要的线程上调用方法,因此将消息发送到。
我想问你一些建议(因为我认为这是一种常见的情况)两种方法中哪种方法最好,或者有更好的方法来实现我想要的。
非常感谢你的帮助。
答案 0 :(得分:2)
消费者 - 生产者很好。 (你在参考文献中提到的那个“答案”问题是一堆蠕虫......想一想......)
您可以使用Queue
,Pipe
,甚至PipedInputStream
和PipedOutputStream
。还有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
...