2017-11-13 4 views
1

Zur Zeit habe ich einen Code wie folgt:Rückkehr Wert nach mehrer Runnable Finish

public String getValue() 
{ 
    StringBuilder builder = new StringBuilder(); 
    // 1st step 
    //some logic to retreive code from database returning value 
    //doing something with the returned value add it to collection 
    builder.append(someString1); 
    // 2nd step 
    //some logic to retreive code from database returning value 
    //doing something with the returned value add it to collection 
    builder.append(someString2); 
    // 3rd step 
    //some logic to retreive code from database returning value 
    //doing something with the returned value add it to collection 
    builder.append(someString3); 

    return builder.toString(); 
} 

ich über Runnable-Objekt gelesen habe, die verwendet werden können, Prozess in mehr Thread zu spalten, die wie meinen Code in etwas ändern gehen dies:

public String getValue() 
{ 
    Thread firstTread = new Thread(new Process1()); 
    firstTread.start(); 
    Thread secondTread = new Thread(new Process1()); 
    secondTread.start(); 
    Thread thirdTread = new Thread(new Process1()); 
    thirdTread.start(); 

    // here i got confuse how to determine whether all thread allready finished 
    // before returning builder.toString(); 
} 
//this is internal class 
class Process1 implements Runnable 
{ 
    public void run() 
    { 
     //do something and add to StringBuilder 
    } 
} 

class Process2 implements Runnable 
{ 
    public void run() 
    { 
     //do something and add to StringBuilder 
    } 
} 

class Process3 implements Runnable 
{ 
    public void run() 
    { 
     //do something and add to StringBuilder 
    } 
} 

Wie kann ich erreichen, dass mein Ziel, den Prozess in mehr Thread zu spalten?

+0

Es wäre einfacher, eine ExecutorService zu verwenden. – assylias

+1

Es stört dich nicht, dass die Saiten in anderer Reihenfolge sein könnten? – Stefan

+0

Ist das für Java 8? – daniu

Antwort

3

Was Sie suchen, ist nicht Runnable, sondern ein Callable. Im Gegensatz zu Runnable gibt eine Callable einen Wert zurück. Dies wird normalerweise zusammen mit ExecutorService (ein Thread-Pool) verwendet.

Es ist immer gut, Ihre Threads in einem Thread-Pool zu verwalten, anstatt sie manuell zu erzeugen. Dies verhindert unnötige und teure Erstellung von Threads. Die Idee ist, statt Thread.start() die Instances von Callable an Ihre ExecutorService Instanz mit vordefinierter Anzahl von Threads zu senden. Jede Einreichung gibt ein Objekt Future zurück. Mit Future Object können Sie auf den Rückgabewert der Callable-Instanzen warten, die Sie an den ExecutorService gesendet haben.

Hier wird Version Ihrer ursprünglichen Code überarbeitet:

class Process1 implements Callable<String> { 
    @Override 
    public String call() throws Exception { 
     return "Some string from this callable"; 
    } 
} 
// Insert implementation for Process2 and Process2 Callables 
    ... 

public static void main(String[] args) throws Exception { 
    ExecutorService executor = Executors.newFixedThreadPool(3); 

    Future<String> process1Future = executor.submit(new Process1()); 
    Future<String> process2Future = executor.submit(new Process2()); 
    Future<String> process3Future = executor.submit(new Process3()); 

    // It will wait here 
    String processedStringByProcess1 = process1Future.get(); 
    String processedStringByProcess2 = process2Future.get(); 
    String processedStringByProcess3 = process3Future.get(); 

    StringBuilder builder = new StringBuilder(); 
    builder.append(processedStringByProcess1); 
    builder.append(processedStringByProcess2); 
    builder.append(processedStringByProcess3); 

    System.out.println(builder.toString()); 
} 
+0

Vielen Dank für die Antwort – user776550

2

Sie verwenden Callable, die so ziemlich eine Runnable Rückgabe eines Werts ist. Und Sie verwenden eine ExecutorService anstatt Thread Objekte selbst zu erstellen.

public String getValue() 
{ 
    ExecutorService threaded = Executors.newFixedThreadPool(NUM_THREADS); 
    List<CompletableFuture> results = threaded.invokeAll(
     Arrays.asList(this::process1, this::process2, this::process3); 
    results.stream() 
     .map(Future::get) // collects the result from each thread 
     .collect(Collectors.joining()); 
} 
private String process1() { return "1"; } 
private String process2() { return "2"; } 
private String process3() { return "3"; } 

EDIT: Beachten Sie, dass die Ausgabe nicht "in einer anderen Reihenfolge" sein wird, weil invokeAll returns "A list of Futures representing the tasks, in the same sequential order as produced by the iterator for the given task list".

+0

Vielen Dank für die Antwort – user776550

0

Es gibt andere Alternativen für die Parallelisierung Ihre Arbeit, aber Ihre direkte Frage zu beantworten, wie ein Thread zu Ende warten, können Sie

firstTread.join(); 
secondTread.join(); 
thirdTread.join(); 
3

Callable passt besser für diese Aufgabe verwenden, weil es Ergebnis zurückgibt.

ExecutorService hilft Thread Management zu verkapseln.

public static void main(String[] args) throws Exception { 
    ExecutorService executorService = Executors.newFixedThreadPool(3); 
    List<Future<String>> futures = new ArrayList<>(); 
    futures.add(executorService.submit(new Process1())); 
    futures.add(executorService.submit(new Process2())); 
    futures.add(executorService.submit(new Process3())); 

    StringBuilder sb = new StringBuilder(); 
    for (Future<String> future : futures) { 
     // handle exceptions 
     sb.append(future.get()); 
    } 
    }