2010-09-18 11 views
10

¿Cómo puedo pedir hilos en el orden en que se crearon las instancias.e.g. ¿Cómo puedo hacer que el programa de abajo imprima los números 1 ... 10 en orden?Ordenar hilos para que se ejecuten en el orden en que se crearon/iniciaron

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

Entonces, ¿cuál es el propósito del uso de los hilos? Use un código secuencial en su lugar – yassin

+5

, este fue solo un código simple para ilustración, en realidad tengo algunas partes que quiero ejecutar en paralelo y luego una vez que se generan los resultados quiero fusionar los resultados en cierto orden – keshav84

+0

comenzando un hilo en el camino La ilustración anterior no es legible, intente asignar el ejecutable a una variable de referencia, que lo hará más legible –

Respuesta

12

suena como usted quiere ExecutorService.invokeAll, que devolverá resultados de subprocesos de trabajo en un orden fijo, a pesar de que pueden ser programadas en orden arbitrario:

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

Agradable. Una diferencia entre esto y las soluciones de Fly y mis es que esto produce toda la producción en un solo bloque al final, mientras que nuestras soluciones producen cada bit de salida a medida que se hace posible. Dependiendo de lo que el PO realmente está haciendo, él podría preferir uno u otro. O no, por supuesto. Sería bueno si hubiera una invocación. Todas las variantes que devolvieron un iterador en lugar de una lista. –

+0

@Tom Anderson, ¿cómo manejarías la interrupción en un 'iterador'? – finnw

+0

excelente ... esto hace el trabajo para mí gracias. la operación de fusión en mi caso permite que esto se optimice más ya que el resultado producido por la tarea 'n' se puede combinar con el resultado de 'n + 1', ¿es posible lograr esto con callables y futuros tales que si alguno de los completos invocables, entonces podemos ejecutar el paso de fusión o que el hilo principal puede ejecutar la fusión con la tarea n + 1 – keshav84

4

En pocas palabras, la programación de los hilos es indeterminada.

http://www.janeg.ca/scjp/threads/scheduling.html dominio Muerto - no haga clic

WaybackMachine version of the above page

La respuesta larga es que si usted quiere hacer esto, tendrá que esperar manualmente para cada hilo para completar su labor antes de permitir que otro se ejecute. Tenga en cuenta que de esta manera, todos los hilos seguirán intercalados pero no realizarán ningún trabajo hasta que usted dé el visto bueno. Eche un vistazo a la palabra reservada de sincronización.

+0

No se trata de hacer que los hilos se ejecuten en un orden determinado (a pesar de lo que dijo el OP), sino que produce en un orden dado Todavía puede ejecutar los hilos en paralelo, siempre que haya una forma de coordinar su salida. –

+0

@Tom Respondí la pregunta cuando parecía simplemente una pregunta académica. Así que, gracias por su comentario pero respondí lo que preguntó :) –

+0

No, incluso en la primera versión de esta pregunta, el OP preguntó "¿cómo puedo hacer que el siguiente programa imprima los números 1 ... 10 en orden" lo que hace está claro que está hablando de ordenar la * salida * de los hilos, no sus ejecuciones. Para mí, al menos. –

1

Si necesita un control detallado, no debe usar subprocesos, sino buscar utilizando un Ejecutor adecuado con Callables o Runnables. Vea la clase de ejecutores para una amplia selección.

+0

¿Te refieres a 'Executors.newSingleThreadExecutor()'? En función de la respuesta del OP a [la respuesta de Peter DeWeese] (http://stackoverflow.com/questions/3741765/order-threads-to-run-in-the-order-they-were-created-started/3741815#3741815) No creo que esto sea lo que ellos quieren. – finnw

+0

"Terminar en cierto orden" ... Eso es complicado. –

3

Puede encadenarlos, es decir, haga que el primero inicie el segundo, el segundo inicie el tercero, etc. Realmente no se ejecutarán al mismo tiempo, excepto un poco de superposición cuando se inicie cada uno .

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

hola peter, lo siento, debería haber mencionado esto antes. No quiero que los hilos se ejecuten uno tras otro Quiero que comiencen juntos, ya que mi objetivo es ejecutar algunas partes en paralelo y luego quiero terminar los hilos en un cierto orden. También agregué este comentario mucho más adelante justo debajo de la pregunta – keshav84

+0

No es necesario votar, a quien hizo eso. Estaba trabajando con la pregunta original. –

7

"En realidad tengo algunas partes que quiero para ejecutar en paralelo, y luego una vez que se generan los resultados, quiero combinar los resultados en cierto orden." Gracias, esto aclara lo que estás preguntando.

Puede ejecutarlos todos a la vez, pero lo importante es obtener sus resultados en orden cuando los hilos finalizan su cálculo. O bien Thread#join() en el orden en el que desea obtener sus resultados, o simplemente Thread#join() y repítelos para obtener sus resultados.

// 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

De esta manera no se puede superponer el cálculo y la fusión de resultados (lo cual se hace secuencialmente) – yassin

+0

Eso podría ser cierto si los subprocesos necesitan seguir ejecutándose --- haciendo más cálculos después de obtener su 'resultado', pero entendí el problema para necesitar hacer una tarea en el hilo. Si los hilos necesitan continuar sus cálculos, la solución sería usar 'worker.wait()' en cada ciclo porque tienes que esperar() en lugar de join() para los resultados para poder imprimirlos fuera. – jbindel

+0

Otra posibilidad para obtener resultados de un "trabajador" que nunca termina sería hacer que cada "trabajador" devuelva la llamada a algún objeto de colección con su resultado cuando el resultado esté disponible, pero parece más complicado que la pregunta original. – jbindel

1

Una solución simple sería la de utilizar una matriz A de cerraduras (una cerradura por hilo). Cuando el hilo i comienza sus ejecuciones, adquiere su cerradura asociada A[i]. Cuando esté listo para fusionar sus resultados, liberará su bloqueo A[i] y esperará a que se liberen los bloqueos A[0], A[1], ..., A[i - 1]; luego combina los resultados.

(En este contexto, significa que el hilo ii -ésimo lanzó hilo)

No sé qué clases para usar en Java, pero debe ser fácil de implementar. Puede comenzar a leer this.

Si tiene más preguntas, no dude en preguntar.

+0

Cuando el hilo principal controla la recopilación de resultados, una forma idiomática de esperar que termine un hilo es llamar a 'Thread # join()'. Su solución para que cada resultado sea un "futuro" que depende del próximo resultado futuro también puede ser útil en algunas situaciones, pero parece más complicado que 'Thread # join()'. – jbindel

+0

Si cada trabajador de alguna manera depende de otro trabajador, uno podría poner las dependencias en los hilos de trabajo. También trabajaría para que el hilo principal controle la interacción de los resultados y realice cualquier cálculo de post/fusión para mantener a los trabajadores lo más simple posible. – jbindel

2

Aquí está una manera de hacerlo sin tener un hilo maestro que espera cada resultado. En cambio, haga que los subprocesos de trabajo compartan un objeto que ordena los resultados.

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

Si tiene una gran cantidad de subprocesos, es posible que desee algo un poco más inteligente que una lista de arrays, por lo que no tendrá todos los resultados anteriores. Tal vez un montón, ordenado por número de orden, donde la raíz solo aparece si tiene el siguiente número de orden no entregada. –

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

de control de orden de ejecución de rosca puede ser implementado fácilmente con los semáforos. El código adjunto se basa en las ideas presentadas en el libro de Schildt sobre Java (La referencia completa ...). // Basado en las ideas presentadas en: // Schildt H .: 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); 
    } 
} 
Cuestiones relacionadas