2012-09-01 88 views
2

在Java中,如何將對象從工作線程傳遞迴主線程?以下面的代碼爲例:在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); 
    } 
} 

如何通過resultmainresults[i]

如何通過thisWorkerThread

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

,以便它可以

mainThread.reults[i] = Processor.process(inputs[i]); 
+1

你真的應該只使用'Executors.newFixedThreadPool(numThreads).invokeAll(...)' – oldrinb

+0

@veer爲什麼?我最多隻能運行10個線程。 – JackWM

回答

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 
    } 
} 
+0

我同意你使用Callable,Future和ExecutorService類;並提供了一個體面的例子,在這裏提供:https://blogs.oracle.com/CoreJavaTechTips/entry/get_netbeans_6 –

1

一個soluton是使用在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

不,這是錯誤的。 ICallback的回調方法將在工作線程中運行。這個答案沒有概述將線程安全的方式將結果從worker的內存移動到主線程的內存。 –

+1

@TimBender:我不會那樣做(現在我們有java.util.concurrent),但通過適當的同步就可以完成。 – Thilo

+0

@Thilo,我認爲OP對Java感到困惑,似乎認爲它在分配引用時的行爲與C++相似。 OP真正需要看到的是在這個答案中'addResult'的實現是什麼,並且我沒有看到它被提供。與回調相反,只需傳遞整個'results'數組,一個同步'List'或'BlockingQueue'都將是優先簡單的解決方案。 –

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... 
} 

你仍然需要工作線程的結果安排以某種方式插入到結果[]數組。作爲一種可能性,您可以通過將數組和索引傳遞給每個工作線程並讓工作線程在結束之前分配結果來完成此操作。

0

一些典型的解決方案是:

  • 握住結果工作線程的情況下(無論是RunnableThread)。這與使用Future接口類似。
  • 使用BlockingQueue表示工作線程可以用來將結果放入其中。
  • 只需使用ExecutorServiceCallable接口即可得到一個Future,可以詢問結果。
0

它看起來像你的目標是並行執行計算,然後一旦所有結果都可用於主線程,它可以繼續並使用它們。

如果是這種情況,請將您的並行計算實現爲Callable而不是線程。將這一組任務傳遞給ExecutorServiceinvokeAll()方法。此方法將阻止,直到所有任務完成,然後您的主線程可以繼續。

1

@ Thilo's和@ 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。如果您不這樣做,則主線程有時會在結果對象中看到陳舊的值,有可能會出現的風險。 join還確保main線程在相應的子線程完成之前不會嘗試訪問結果。

+0

感謝您提出主線程需要在每個工作線程上調用join()。 –

0

我想我有一個更好的解決方案,爲什麼不讓你的工作線程把結果傳遞給一個linkedListBlockingQueue,傳遞給他們,完成後,你的主函數從隊列中選擇結果這樣

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 
} 
相關問題