在Java中,如何将对象从工作线程传递回主线程?

时间:2012-09-01 00:14:38

标签: java multithreading

在Java中,如何将对象从工作线程传递回主线程?以下面的代码为例:

  main(String[] args) {

    String[] inputs;
    Result[] results;
    Thread[] workers = new WorkerThread[numThreads];

    for (int i = 0; i < numThreads; i++) {
        workers[i] = new WorkerThread(i, inputs[i], results[i]);
        workers[i].start();
    } 

    ....
  }
  ....

class WorkerThread extends Thread {
    String input;
    int name;
    Result result;

    WorkerThread(int name, String input, Result result) {
        super(name+"");
        this.name = name;
        this.input = input;
        this.result = result;
    }

    public void run() {
        result  = Processor.process(input);
    }
}

如何将result传递回main的{​​{1}}?

如何将results[i]传递给this

WorkerThread

所以它可以

workers[i] = new WorkerThread(i, inputs[i], results[i], this);

7 个答案:

答案 0 :(得分:5)

为什么不使用CallablesExecutorService

main(String[] args) {

  String[] inputs;
  Future<Result>[] results;

  for (int i = 0; i < inputs.length; i++) {
    results[i] = executor.submit(new Worker(inputs[i]);
  } 
  for (int i = 0; i < inputs.length; i++) {
    Result r = results[i].get();
    // do something with the result
  }
}

答案 1 :(得分:1)

一个解决方案是在WorkerThread中使用回调:

class WorkerThread extends Thread {
    ICallback callback;
    ...

    WorkerThread(int name, String input, Result result, ICallback callback) {
        super(name+"");
        this.callback = callback;
    ...
    }

    public void run() {
        result  = Processor.process(input);
        callback.addResult(result);
    }

}

您的调用类将实现addResult并添加到result数组。

答案 2 :(得分:1)

@ Thilo和@ Erickson的答案是最好的答案。现有的API可以简单可靠地完成这类工作。

但是如果你想坚持现有的手工操作方法,那么对你的代码进行以下更改可能就足够了:

for (int i = 0; i < numThreads; i++) {
    results[i] = new Result();
    ...
    workers[i] = new WorkerThread(i, inputs[i], results[i]);
    workers[i].start();
}

...

public void run() {
    Result tmp = Processor.process(input);
    this.result.updateFrom(tmp);
    // ... where the updateFrom method copies the state of tmp into
    // the Result object that was passed from the main thread.
}

另一种方法是用Result[]替换主程序中的Result[][],并将Result[0]传递给可以使用结果对象更新的子线程。 (轻量级支架)。

然而,当你在低级别实现它时,我们有一个重要的问题是主线程需要在尝试检索结果之前在所有子线程上调用Thread.join。如果不这样做,则主线程偶尔会看到Result对象中的陈旧值存在风险。 join还确保main线程在相应的子线程完成之前不会尝试访问Result。

答案 3 :(得分:0)

主线程需要等待工作线程完成才能获得结果。一种方法是让主线程在尝试读取结果之前等待每个工作线程终止。线程在run()方法完成时终止。

例如:

for (int i = 0; i < workers.length; i++) {
  worker.join(); // wait for worker thread to terminate
  Result result = results[i]; // get the worker thread's result
  // process the result here...
}

您仍然必须安排将工作线程的结果以某种方式插入到result []数组中。作为一种可能性,您可以通过将数组和索引传递到每个工作线程并让工作线程在终止之前分配结果来完成此操作。

答案 4 :(得分:0)

一些典型的解决方案是:

  • 将结果保存在工作线程的实例中(无论是Runnable还是Thread)。这类似于使用Future接口。
  • 使用构造工作线程的BlockingQueue,可以将结果放入其中。
  • 简单地使用ExecutorServiceCallable界面获取可以询问结果的Future

答案 5 :(得分:0)

看起来你的目标是并行执行计算,然后一旦所有结果都可用于主线程,它就可以继续并使用它们。

如果是这种情况,请将并行计算实现为Callable而不是线程。将此任务集合传递给ExecutorService的{​​{3}}方法。此方法将阻塞,直到所有任务都完成,然后您的主线程可以继续。

答案 6 :(得分:0)

我认为我有一个更好的解决方案,为什么不让你的工作线程将结果传递给一个linkedListBlockingQueue,它们在完成后传递给它们,你的main函数从队列中选择结果此

while(true){linkedListBlockingQueue.take(); 
    //todo: fil in the task you want it to do
    //if a specific kind of object is returned/countdownlatch is finished exit
}