2010-09-18 2 views
10

Как я могу упорядочить потоки в том порядке, в котором они были созданы. как я могу сделать приведенную ниже программу печатать цифры 1 ... 10 по порядку.Заказ потоков для запуска в том порядке, в котором они были созданы/запущены

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

В чем же цель использования потоков? Вместо этого используйте порядковый код – yassin

+5

, это был просто простой код для иллюстрации. На самом деле у меня есть некоторые части, которые я хочу выполнить параллельно, а затем, как только результаты будут сгенерированы, я хочу объединить результаты в определенном порядке. – keshav84

+0

, начиная нить в пути показанный выше, нигде не читается, попробуйте присвоить runnable ссылочной переменной, что сделает его более читаемым –

ответ

12

Похоже, вы хотите ExecutorService.invokeAll, который будет возвращать результаты из рабочих потоков в определенном порядке, несмотря на то, что они могут быть назначены в произвольном порядке:

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

Nice. Разница между этим и Fly и моими решениями заключается в том, что в конце он выводит весь выход в один кусок, тогда как наши решения производят каждый бит вывода, когда это становится возможным. В зависимости от того, что фактически делает ОП, он может предпочесть тот или иной. Или нет, конечно. Было бы неплохо, если бы был вариант invokeAll, который возвращал Iterator, а не список. –

+0

@Tom Anderson, как бы вы справились с прерыванием в «Итераторе»? – finnw

+0

превосходно .. это делает работу для меня спасибо u. Операция слияния в моем случае позволяет оптимизировать ее, поскольку результат, созданный задачей «n», может быть объединен с результатом «n + 1», можно ли это сделать с помощью вызовов и фьючерсов, так что если какой-либо один из вызываемого завершается, то мы можем выполнить шаг слияния или что основной поток разрешен для выполнения слияния с задачей n + 1 – keshav84

4

Проще говоря, планирование потоков является неопределенным.

http://www.janeg.ca/scjp/threads/scheduling.html Мертвый домен - не кликайте

WaybackMachine version of the above page

Чем дольше ответ, что если вы хотите сделать это, вам нужно вручную ждать каждого потока, чтобы завершить свою работу прежде чем вы разрешите другому запустить. Обратите внимание, что таким образом все потоки все равно будут чередоваться, но они не будут выполнять какую-либо работу, пока вы не дадите добро. Посмотрите на синхронизированное зарезервированное слово.

+0

. Речь идет не о том, что потоки выполняются в определенном порядке (несмотря на то, что сказал OP), но производят выходные данные в определенном порядке. Вы все равно можете запускать потоки параллельно, если есть способ координировать их вывод. –

+0

@Tom Я ответил на вопрос, когда он выглядел просто как академический вопрос. Итак, спасибо за ваш комментарий, но я ответил на то, что он спросил :) –

+0

Нет, даже в самой ранней версии этого вопроса, ОП спросил: «Как я могу сделать следующую программу, напечатать цифры 1 ... 10 по порядку», что делает ясно, что он говорит о том, чтобы упорядочить * выход * потоков, а не их исполнение. Для меня, по крайней мере. –

1

Если вам нужен этот мелкозернистый элемент управления, вы не должны использовать потоки, а вместо этого смотрите на использование подходящего Исполнителя с Callables или Runnables. См. Класс «Исполнители» для широкого выбора.

+0

Вы ссылаетесь на 'Executors.newSingleThreadExecutor()'? Основываясь на ответе OP на ответ Питера Дэвиса (http://stackoverflow.com/questions/3741765/ordering-threads-to-run-in-the-order-they-were-created-started/3741815#3741815) Я не думаю, что это то, чего они хотят. – finnw

+0

«Конец в определенном порядке» ... Это сложный вопрос. –

3

Вы можете связать их, то есть первыми начать второй, второй запустить третий и т. Д. Они не будут работать одновременно, за исключением небольшого перекрытия при каждом запуске ,

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

привет, я сожалею, я должен был упомянуть об этом раньше. Я не хочу, чтобы потоки запускались один за другим, я хочу, чтобы они начали работать вместе, поскольку моя цель состоит в том, чтобы выполнять некоторые части параллельно, а затем я хочу закончить потоки в определенном порядке. Я также добавил этот комментарий намного позже чуть ниже вопроса – keshav84

+0

Нет необходимости проголосовать, кому бы это ни было. Я работал с оригинальным вопросом. –

7

«Я на самом деле есть некоторые детали, которые я хочу, чтобы выполнить параллельно, а затем, как только результаты генерируются, я хочу, чтобы объединить результаты в определенном порядке.» Спасибо, это уточняет, о чем вы спрашиваете.

Вы можете запускать их все сразу, но важно, чтобы их результаты были в порядке, когда потоки завершат их вычисления. Либо Thread#join() их в том порядке, в котором вы хотите получить их результаты, либо просто Thread#join() их всех, а затем повторите их, чтобы получить их результаты.

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

Таким образом, вы не можете перекрывать вычисления и слияние результатов (что делается последовательно) – yassin

+0

Это может быть правдой, если потоки должны продолжать работать - делать больше вычислений после получения их «результата», но я понял, проблема, которая должна выполняться одной задачей в потоке. Если потокам необходимо продолжить вычисления, тогда решение будет использовать 'worker.wait()' в каждом цикле, потому что вам нужно ждать(), а не join() для получения результатов, чтобы иметь возможность распечатывать их вне. – jbindel

+0

Другая возможность получения результатов от «рабочего», который никогда не заканчивается, - это заставить каждого «рабочего» сделать обратный вызов для какого-либо объекта коллектора с его результатом, поскольку его результат стал доступным, но это кажется более сложным, чем исходный вопрос. – jbindel

1

Простое решение было бы использовать массив A замков (один замок для каждого потока). Когда поток i начинает выполнение, он получает связанный с ним замок A[i]. Когда он будет готов объединить свои результаты, он освободит свой замок A[i] и ждет блокировок A[0], A[1], ..., A[i - 1]; то он объединяет результаты.

(В этом контексте нить i означает i -м начал нить)

Я не знаю, какие классы использовать в Java, но это должно быть легко осуществить. Вы можете начать читать this.

Если у вас есть дополнительные вопросы, не стесняйтесь спрашивать.

+0

Когда основной поток контролирует сбор результатов, идиоматический способ дождаться окончания потока - это вызов 'Thread # join()'. Ваше решение о том, чтобы каждый результат был «будущим», который зависит от следующего будущего результата, может быть полезным и в некоторых ситуациях, но он кажется более сложным, чем «Thread # join()». – jbindel

+0

Если каждый работник каким-то образом зависит от другого работника, можно установить зависимости в рабочих потоках. Было бы также работать, чтобы основная нить контролировала взаимодействие результатов и выполняла любые пост-слияния вычислений, чтобы максимально упростить работу. – jbindel

2

Вот способ сделать это без мастер-нить который ждет каждого результата. Вместо этого, рабочие потоки совместно используют объект, который заказывает результаты.

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

Если у вас большое количество потоков, вы можете захотеть чего-то более умного, чем аррайалист, так что у вас нет всех старых результатов. Может быть, куча, упорядоченная по номеру заказа, где корень только выскочил, если у него есть следующий недостижимый номер заказа. –

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

Контроль потока выполнения заказа может быть реализована довольно легко с семафорами. Приведенный код основан на идеях, представленных в книге Шильдта по Java (полная ссылка ....). // На основе идей, представленных в: // 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); 
    } 
} 
Смежные вопросы