Упорядочивание потоков в том порядке, в котором они были созданы / запущены - PullRequest
10 голосов
/ 18 сентября 2010

Как мне упорядочить потоки в том порядке, в котором они были созданы. Например, как заставить приведенную ниже программу печатать числа 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 ]

12 голосов
/ 18 сентября 2010

Звучит так, как вы хотите <a href="http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html#invokeAll%28java.util.Collection%29" rel="noreferrer">ExecutorService.invokeAll</a>, который будет возвращать результаты из рабочих потоков в фиксированном порядке, даже если они могут быть запланированы в произвольном порядке:

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();
        }
    }

}
7 голосов
/ 18 сентября 2010

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

Вы можете запустить их все сразу, но главное - привести их результаты в порядок, когда потоки закончат свои вычисления.Либо 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());
        }
    }
}
4 голосов
/ 18 сентября 2010

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

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

WaybackMachine версия вышеуказанной страницы

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

3 голосов
/ 18 сентября 2010

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

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();
    }
}
2 голосов
/ 18 сентября 2010

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

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);
    }
}
1 голос
/ 09 декабря 2012
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();
}
1 голос
/ 18 сентября 2010

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

(В этом контексте поток i означает i -й запущенный поток)

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

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

1 голос
/ 18 сентября 2010

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

0 голосов
/ 02 июня 2018

Это можно сделать без использования синхронизированного ключевого слова и с помощью ключевого слова volatile . Ниже приведен код.

package threadOrderingVolatile;

public class Solution {
    static volatile int counter = 0;
    static int print = 1;
    static char c = 'A';

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread[] ths = new Thread[4];
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new Thread(new MyRunnable(i, ths.length));
            ths[i].start();
        }
    }

    static class MyRunnable implements Runnable {
        final int thID;
        final int total;

        public MyRunnable(int id, int total) {
            thID = id;
            this.total = total;
        }

        @Override
        public void run() {
            while(true) {
                if (thID == (counter%total)) {
                    System.out.println("thread " + thID + " prints " + c);
                    if(c=='Z'){
                        c='A';
                    }else{
                        c=(char)((int)c+1);
                    }
                    System.out.println("thread " + thID + " prints " + print++);
                    counter++;                  
                } else {
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        // log it
                    }
                }
            }
        }

    }

}

Ниже приведена ссылка на github, в которой есть файл readme, в котором подробно объясняется, как это происходит. https://github.com/sankar4git/volatile_thread_ordering

0 голосов
/ 10 мая 2017

Управление порядком выполнения потоков может быть реализовано довольно просто с помощью семафоров. Прилагаемый код основан на идеях, представленных в книге Шильдта о 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...