2010-09-18 38 views
10

Wie kann ich Threads in der Reihenfolge bestellen, in der sie instanziiert wurden.e.g. Wie kann ich das folgende Programm die Zahlen 1 ... 10 in Reihenfolge drucken lassen?Reihenfolge der Threads in der Reihenfolge, in der sie erstellt/gestartet wurden

public class ThreadOrdering { 
    public static void main(String[] args) { 

     class MyRunnable implements Runnable{ 
      private final int threadnumber; 

      MyRunnable(int threadnumber){ 
       this.threadnumber = threadnumber; 
      } 

      public void run() { 
       System.out.println(threadnumber); 
      } 
     } 

     for(int i=1; i<=10; i++){ 
      new Thread(new MyRunnable(i)).start(); 
     } 
    } 
} 
+10

Was ist dann der Zweck der Verwendung von Threads? Verwenden Sie einen sequentiellen Code stattdessen – yassin

+5

dies nur eine einfache Code zur Veranschaulichung war, ich tatsächlich einige Teile, die ich parallel ausführen will und dann, sobald die Ergebnisse generiert werden, möchte ich die Ergebnisse in bestimmten Reihenfolge fusionieren – keshav84

+0

einen Thread in der Art und Weise beginnen oben dargestellt ist bei weitem nicht lesbar ist, versuchen, die runnable zu einer Referenzgröße zuweisen, das wird es –

Antwort

12

Klingt wie Sie ExecutorService.invokeAll wollen, die Ergebnisse von Arbeitsthreads in einer festen Reihenfolge zurückkehren, auch wenn sie in beliebiger Reihenfolge geplant werden kann:

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.Callable; 
import java.util.concurrent.ExecutionException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 

public class ThreadOrdering { 

    static int NUM_THREADS = 10; 

    public static void main(String[] args) { 
     ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS); 
     class MyCallable implements Callable<Integer> { 
      private final int threadnumber; 

      MyCallable(int threadnumber){ 
       this.threadnumber = threadnumber; 
      } 

      public Integer call() { 
       System.out.println("Running thread #" + threadnumber); 
       return threadnumber; 
      } 
     } 

     List<Callable<Integer>> callables = 
      new ArrayList<Callable<Integer>>(); 
     for(int i=1; i<=NUM_THREADS; i++) { 
      callables.add(new MyCallable(i)); 
     } 
     try { 
      List<Future<Integer>> results = 
       exec.invokeAll(callables); 
      for(Future<Integer> result: results) { 
       System.out.println("Got result of thread #" + result.get()); 
      } 
     } catch (InterruptedException ex) { 
      ex.printStackTrace(); 
     } catch (ExecutionException ex) { 
      ex.printStackTrace(); 
     } finally { 
      exec.shutdownNow(); 
     } 
    } 

} 
+0

Schön. Ein Unterschied zwischen diesem und Flys und meinen Lösungen besteht darin, dass dies die gesamte Ausgabe in einem Stück am Ende produziert, während unsere Lösungen jedes Bit der Ausgabe erzeugen, wie es möglich wird. Je nachdem, was der OP gerade macht, könnte er das eine oder andere bevorzugen. Oder natürlich nicht. Es wäre schön, wenn es eine InvokeAll-Variante gäbe, die einen Iterator statt einer Liste zurückliefern würde. –

+0

@Tom Anderson, wie würdest du mit Unterbrechungen in einem 'Iterator' umgehen? – finnw

+0

super .. das macht den Job für mich danke dir. die Merge-Operation in meinem Fall ermöglicht dies optimiert weiter, da das Ergebnis von Task 'n' mit Ergebnis von 'n + 1 zusammengeführt werden kann, ist es möglich, dies mit Callables und Futures zu erreichen, dass wenn jemand der aufrufbar ist abgeschlossen, dann können wir den Zusammenführungsschritt ausführen oder dass der Hauptthread die Zusammenführung mit Task n + 1 ausführen kann – keshav84

4

Einfach gesagt, ist die Planung von Threads unbestimmt.

http://www.janeg.ca/scjp/threads/scheduling.html Toten Domain - klicken Sie nicht

WaybackMachine version of the above page

Die längere Antwort ist, dass, wenn Sie dies tun wollen, müssen Sie manuell für jeden Thread warten, um seine Arbeit abzuschließen bevor du einem anderen erlaubst zu rennen. Beachten Sie, dass auf diese Weise alle Threads verschachtelt werden, aber sie werden keine Arbeit leisten, bis Sie grünes Licht geben. Sehen Sie sich das reservierte Synchronwort an.

+0

Dies ist nicht darüber, dass die Fäden in einer gegebenen Reihenfolge ausgeführt werden (ungeachtet dem, was die OP gesagt), aber Ausgabeerzeugungs in einer bestimmten Reihenfolge. Sie können die Threads weiterhin parallel ausführen, solange es möglich ist, ihre Ausgaben zu koordinieren. –

+0

@Tom Ich beantwortete die Frage, als es nur wie eine akademische Frage aussah. Also, vielen Dank für Ihren Kommentar, aber ich antwortete, was er fragte :) –

+0

Nein, auch in der frühesten Version dieser Frage, fragte der OP „Wie kann ich das folgende Programm mache die Zahlen 1 ... 10, um drucken“, was macht es ist klar, er spricht über die Bestellung der * Ausgang * der Threads, nicht ihre Ausführungen. Für mich zumindest. –

1

Wenn Sie diese feinkörnige Steuerung benötigen, sollten Sie keine Threads verwenden, sondern stattdessen einen geeigneten Executor mit Callables oder Runnables verwenden. Siehe die Executors-Klasse für eine große Auswahl.

+0

Beziehen Sie sich auf 'Executors.newSingleThreadExecutor()'? Basierend auf der Antwort des OP auf [Peter DeWeese Antwort] (http://stackoverflow.com/questions/3741765/ordering-threads-to-run-in-the-order-they-were-created-started/3741815#3741815) Ich glaube nicht, dass sie das wollen. – finnw

+0

"End in einer bestimmten Reihenfolge" ... Das ist eine schwierige Frage. –

3

Sie können sie verketten - das heißt, haben Sie die erste starten die zweite, die zweite starten die dritte, etc. Sie werden nicht wirklich zur gleichen Zeit mit Ausnahme von ein wenig Überlappung ausgeführt, wenn jeder gestartet wird .

public class ThreadOrdering 
{ 
    public static void main(String[] args) 
    { 
     MyRunnable[] threads = new MyRunnable[10];//index 0 represents thread 1; 
     for(int i=1; i<=10; i++) 
      threads[i] = new MyRunnable(i, threads); 
     new Thread(threads[0].start); 
    } 
} 

public class MyRunnable extends Runnable 
{ 
    int threadNumber; 
    MyRunnable[] threads; 

    public MyRunnable(int threadNumber, MyRunnable[] threads) 
    { 
     this.threadnumber = threadnumber; 
     this.threads = threads; 
    } 

    public void run() 
    { 
     System.out.println(threadnumber); 
     if(threadnumber!=10) 
      new Thread(threadnumber).start(); 
    } 
} 
+0

Hallo Peter, es tut mir leid, ich hätte das früher erwähnen sollen. Ich möchte nicht, dass die Threads nacheinander ausgeführt werden, ich möchte, dass sie zusammen starten, da mein Ziel ist, einige Teile parallel auszuführen und dann die Threads in einer bestimmten Reihenfolge zu beenden. Ich habe auch diesen Kommentar viel später direkt unter der Frage – keshav84

+0

Keine Abstimmung notwendig, zu wem auch immer das getan. Ich habe mit der ursprünglichen Frage gearbeitet. –

7

„Ich habe tatsächlich einige Teile, die ich parallel ausgeführt werden soll, und dann, sobald die Ergebnisse erzeugt werden, möchte ich die Ergebnisse in bestimmten Reihenfolge verschmelzen.“ Danke, das klärt, was du verlangst.

Sie können sie alle auf einmal ausführen, aber das Wichtigste ist, ihre Ergebnisse in der richtigen Reihenfolge zu erhalten, wenn die Threads ihre Berechnung abgeschlossen haben. Entweder Thread#join() sie in der Reihenfolge, in der Sie ihre Ergebnisse erhalten möchten, oder nur Thread#join() sie alle und dann durchlaufen sie, um ihre Ergebnisse zu erhalten.

// Joins the threads back to the main thread in the order we want their results. 
public class ThreadOrdering { 
    private class MyWorker extends Thread { 
     final int input; 
     int result; 
     MyWorker(final int input) { 
      this.input = input; 
     } 
     @Override 
     public void run() { 
      this.result = input; // Or some other computation. 
     } 
     int getResult() { return result; } 
    } 

    public static void main(String[] args) throws InterruptedException { 
     MyWorker[] workers = new MyWorker[10]; 
     for(int i=1; i<=10; i++) { 
      workers[i] = new MyWorker(i); 
      workers[i].start(); 
     } 

     // Assume it may take a while to do the real computation in the threads. 

     for (MyWorker worker : workers) { 
      // This can throw InterruptedException, but we're just passing that. 
      worker.join(); 
      System.out.println(worker.getResult()); 
     } 
    } 
} 
+0

Auf diese Weise können nicht die Berechnung und die Ergebnisse Verschmelzung überlappen können (die der Reihe nach durchgeführt wird) – yassin

+0

, die wahr sein könnte, wenn die Fäden laufen zu halten brauchen --- mehr Berechnungen zu tun, nachdem sie ihre 'result' bekommen, aber ich verstand die Problem, eine Aufgabe im Thread ausführen zu müssen. Wenn die Threads ihre Berechnungen fortsetzen müssen, wäre die Lösung, 'worker.wait()' in jeder Schleife zu verwenden, da Sie für die Ergebnisse warten() und nicht beitreten() müssen, um sie drucken zu können aus. – jbindel

+0

Eine andere Möglichkeit, Ergebnisse von einem 'worker' zu erhalten, die niemals endet, wäre, dass jeder' worker' ein Callback zu einem collector-Objekt mit seinem Ergebnis macht, sobald das Ergebnis verfügbar wird, aber das erscheint komplizierter als die ursprüngliche Frage. – jbindel

1

wäre eine einfache Lösung, die ein Array A von Schlössern (eine Sperre pro Thread) zu verwenden sein. Wenn der Thread i mit seinen Ausführungen beginnt, erhält er die zugehörige Sperre A[i]. Wenn es bereit ist, seine Ergebnisse zusammenzuführen, gibt es seine Sperre A[i] frei und wartet darauf, dass die Sperren A[0], A[1], ..., A[i - 1] freigegeben werden; dann führt es die Ergebnisse zusammen.

(In diesem Zusammenhang Faden i bedeutet die i -te Thread gestartet)

Ich weiß nicht, welche Klassen in Java zu verwenden, aber es muss einfach zu implementieren sein. Sie können anfangen zu lesen this.

Wenn Sie weitere Fragen haben, zögern Sie nicht zu fragen.

+0

Wenn der Hauptthread die Auflistung der Ergebnisse kontrolliert, ist es eine idiomatische Methode, auf das Ende eines Threads zu warten, indem Sie 'Thread # join()' aufrufen. Ihre Lösung, jedes Ergebnis zu einer "Zukunft" zu machen, die vom nächsten Zukunftsergebnis abhängt, könnte in einigen Situationen ebenfalls nützlich sein, aber es scheint komplizierter als 'Thread # join()'. – jbindel

+0

Wenn jeder Worker irgendwie von einem anderen Worker abhängt, könnte man die Abhängigkeiten in die Worker-Threads einfügen. Es würde auch funktionieren, dass der Hauptthread die Interaktion von Ergebnissen steuert und Post/Merging-Berechnungen durchführt, um die Arbeiter so einfach wie möglich zu halten. – jbindel

2

Hier ist ein Weg, es zu tun, ohne ein Master-Gewinde Das wartet auf jedes Ergebnis. Stattdessen müssen sich die Worker-Threads ein Objekt teilen, das die Ergebnisse ordnet.

import java.util.*; 

public class OrderThreads { 
    public static void main(String... args) { 
     Results results = new Results(); 
     new Thread(new Task(0, "red", results)).start(); 
     new Thread(new Task(1, "orange", results)).start(); 
     new Thread(new Task(2, "yellow", results)).start(); 
     new Thread(new Task(3, "green", results)).start(); 
     new Thread(new Task(4, "blue", results)).start(); 
     new Thread(new Task(5, "indigo", results)).start(); 
     new Thread(new Task(6, "violet", results)).start(); 
    } 
} 

class Results { 
    private List<String> results = new ArrayList<String>(); 
    private int i = 0; 

    public synchronized void submit(int order, String result) { 
     while (results.size() <= order) results.add(null); 
     results.set(order, result); 
     while ((i < results.size()) && (results.get(i) != null)) { 
      System.out.println("result delivered: " + i + " " + results.get(i)); 
      ++i; 
     } 
    } 
} 


class Task implements Runnable { 
    private final int order; 
    private final String result; 
    private final Results results; 

    public Task(int order, String result, Results results) { 
     this.order = order; 
     this.result = result; 
     this.results = results; 
    } 

    public void run() { 
     try { 
      Thread.sleep(Math.abs(result.hashCode() % 1000)); // simulate a long-running computation 
     } 
     catch (InterruptedException e) {} // you'd want to think about what to do if interrupted 
     System.out.println("task finished: " + order + " " + result); 
     results.submit(order, result); 
    } 
} 
+0

Wenn Sie eine große Anzahl von Threads haben, möchten Sie vielleicht etwas klüger als eine Arraylist, so dass Sie nicht alle alten Ergebnisse haben. Vielleicht ein Heap, geordnet nach Bestellnummer, wobei der Root nur dann geclippt wird, wenn er die nächste nicht gelieferte Bestellnummer hat. –

1
public static void main(String[] args) throws InterruptedException{ 
    MyRunnable r = new MyRunnable(); 
    Thread t1 = new Thread(r,"A"); 
    Thread t2 = new Thread(r,"B"); 
    Thread t3 = new Thread(r,"C"); 

    t1.start(); 
    Thread.sleep(1000); 

    t2.start(); 
    Thread.sleep(1000); 
    t3.start(); 
} 
0

Steuerung der Thread-Ausführungsreihenfolge kann mit dem Semaphore ganz einfach implementiert werden. Der beigefügte Code basiert auf den Ideen, die in Schildts Buch über Java vorgestellt wurden (Die vollständige Referenz ....). // Basierend auf den Ideen präsentiert in: // Schildt .: Java.The.Complete.Reference.9th.Edition.

import java.util.concurrent.Semaphore; 

class Manager { 
    int n; 
// Initially red on semaphores 2&3; green semaphore 1. 
    static Semaphore SemFirst = new Semaphore(1); 
    static Semaphore SemSecond = new Semaphore(0); 
    static Semaphore SemThird = new Semaphore(0); 

void firstAction() { 
    try { 
     SemFirst.acquire(); 
    } catch(InterruptedException e) { 
     System.out.println("Exception InterruptedException catched"); 
    } 
    System.out.println("First: "); 
    System.out.println("-----> 111"); 
    SemSecond.release(); 
} 
void secondAction() { 
    try{ 
     SemSecond.acquire(); 
    } catch(InterruptedException e) { 
     System.out.println("Exception InterruptedException catched"); 
    } 
    System.out.println("Second: "); 
    System.out.println("-----> 222"); 
    SemThird.release(); 
} 
void thirdAction() { 
    try{ 
     SemThird.acquire(); 
    } catch(InterruptedException e) { 
     System.out.println("Exception InterruptedException catched"); 
    } 
    System.out.println("Third: "); 
    System.out.println("-----> 333"); 
    SemFirst.release(); 
} 
} 

class Thread1 implements Runnable { 
    Manager q; 

    Thread1(Manager q) { 
    this.q = q; 
    new Thread(this, "Thread1").start(); 
} 

public void run() { 
    q.firstAction(); 
} 
} 

class Thread2 implements Runnable { 
    Manager q; 

    Thread2(Manager q) { 
    this.q = q; 
    new Thread(this, "Thread2").start(); 
} 

public void run() { 
    q.secondAction(); 
} 
} 

class Thread3 implements Runnable { 
    Manager q; 

    Thread3(Manager q) { 
    this.q = q; 
    new Thread(this, "Thread3").start(); 
} 

public void run() { 
    q.thirdAction(); 
} 
} 

class ThreadOrder { 
    public static void main(String args[]) { 
    Manager q = new Manager(); 
    new Thread3(q); 
    new Thread2(q); 
    new Thread1(q); 
    } 
} 
Verwandte Themen