keshav84
keshav84

Reputation: 2301

Ordering threads to run in the order they were created/started

How can i order threads in the order they were instantiated.e.g. how can i make the below program print the numbers 1...10 in order.

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

Upvotes: 12

Views: 38200

Answers (11)

quickbug
quickbug

Reputation: 4848

In case someone needs, this is my take at this problem in Python. My approach is to use a deque. Each instance of the class places itself on the queue, does the working task right at construction, then waits for the previous member of the queue to terminate its output to do his. The trick is that each instance has two locks (aka semaphores) to control printing. One which is copied from the last instance entered in the queue: I wil wait for this lock to print. Another one that is created and locked at construction. The next instance to enter the queue will copy that one and will have to wait for me to release it, which I will do after my printing is done.

import random
from functools import \
    partial  # an object made of a function ready to call with prefilled arguments
import threading, time
from collections import deque

printing_lock = threading.Lock()  # for debuging: avoid threads printing debug infos in the middle of each other


class WorkNowPrintLater:
    def __init__(self, id: int, work_func: partial, print_func: partial, my_queue: deque, queue_lock: threading.Lock):
        """
        Create an instance of this class does the whole thing:
            1/ do some job immediately
            2/ do some other job (usually an output) in the same order as instances were created
        :param id:
            id of this instance. for debug purpose only
        :param work_func:
            the working function.
            Note for non python users: a partial is an object made of a function with its arguments
            already in place, ready to launch
        :param print_func:
            the output function
        :param my_queue:
            a double-end-queue (deque) where each instance of WorkNowPrintLater will put itself on construction
            Must be the same for all instances to synchronize
        :param queue_lock:
            a semaphore to protect access to the queue
            Must be the same for all instances to synchronize
        """
        with printing_lock:
            print(f"{id} being created")
        self.id = id
        self.work_func = work_func
        self.print_func = print_func
        self.my_queue = my_queue
        self.queue_lock = queue_lock
        self.done = False
        self.lock_i_wait_before_i_printing = threading.Lock() if len(my_queue) == 0 else my_queue[
            -1].lock_you_wait_before_you_print
        self.lock_you_wait_before_you_print = threading.Lock()
        self.lock_you_wait_before_you_print.acquire()  # Block access to printer to the next element in the queue until I'm done

        with printing_lock:
            print(f"{self.id} waits for queue lock to put myself in")
        with self.queue_lock:
            self.my_queue.append(self)

        my_worker = threading.Thread(target=self.worker)
        my_worker.start()
        print(f"{id} is alive")

    def worker(self):
        with printing_lock:
            print(f"{self.id} working starts")
        self.work_func()

        with printing_lock:
            print(f"{self.id} working done. wait for printer")
        with self.lock_i_wait_before_i_printing:
            self.print_func()
            self.lock_you_wait_before_you_print.release()
            self.done = True

        with printing_lock:
            print(f"{self.id} waits for queue lock to do housekeeping")
        with self.queue_lock:
            with printing_lock:
                print(f"{self.id} housekeeping starts")
            if len(self.my_queue) <= 1:
                return
            while self.my_queue[0].done and len(self.my_queue) >= 2:
                _ = self.my_queue.popleft()


 """ MAIN PROGRAM """


threads_queue = deque()
semaphore = threading.Lock()


def wait(id):
    t = random.random() * 10
    print(f"{id} is working for {t} seconds")
    time.sleep(t)


def output(id):
    print(f"output {id}")


for i in range(5):
    _ = WorkNowPrintLater(i, partial(wait, i), partial(output, i), threads_queue, semaphore)

Upvotes: 0

sankar banerjee
sankar banerjee

Reputation: 101

This can be done without using synchronized keyword and with the help of volatile keyword. Following is the code.

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

    }

}

Following is the github link which has a readme, that gives detailed explanation about how it happens. https://github.com/sankar4git/volatile_thread_ordering

Upvotes: 0

Marek
Marek

Reputation: 1

Control of thread execution order may be implemented quite easily with the semaphores. The code attached is based on the ideas presented in Schildt's book on Java (The complete reference....). // Based on the ideas presented in: // 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);
    }
}

Upvotes: 0

user124493
user124493

Reputation:

Simply put, the scheduling of threads is indeterminate.

http://www.janeg.ca/scjp/threads/scheduling.html Dead domain - do not click

WaybackMachine version of the above page

The longer answer is that if you want to do this, you'll need to manually wait for each thread to complete its work before you allow another to run. Note that in this fashion, all the threads will still interleave but they won't accomplish any work until you give the go-ahead. Have a look at the synchronize reserved word.

Upvotes: 5

Diana
Diana

Reputation: 1615

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

Upvotes: 1

finnw
finnw

Reputation: 48629

Sounds like you want ExecutorService.invokeAll, which will return results from worker threads in a fixed order, even though they may be scheduled in arbitrary order:

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

}

Upvotes: 15

Tom Anderson
Tom Anderson

Reputation: 47193

Here's a way to do it without having a master thread that waits for each result. Instead, have the worker threads share an object which orders the results.

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

Upvotes: 2

yassin
yassin

Reputation: 6707

A simple solution would be to use an array A of locks (one lock per thread). When thread i begins its executions, it acquires its associated lock A[i]. When it's ready to merge its results, it releases its lock A[i] and waits for locks A[0], A[1], ..., A[i - 1] to be released; then it merges the results.

(In this context, thread i means the i-th launched thread)

I don't know what classes to use in Java, but it must be easy to implement. You can begin reading this.

If you have more questions, feel free to ask.

Upvotes: 1

jbindel
jbindel

Reputation: 5635

"I actually have some parts that i want to execute in parallel, and then once the results are generated, I want to merge the results in certain order." Thanks, this clarifies what you're asking.

You can run them all at once, but the important thing is to get their results in order when the threads finish their computation. Either Thread#join() them in the order in which you want to get their results, or just Thread#join() them all and then iterate through them to get their results.

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

Upvotes: 10

Peter DeWeese
Peter DeWeese

Reputation: 18333

You can chain them – that is, have the first one start the second, the second start the third, etc. They won't really be running at the same time except for a bit of overlap when each one is started.

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

Upvotes: 4

If you need that fine-grained control, you should not use threads but instead look into using a suitable Executor with Callables or Runnables. See the Executors class for a wide selection.

Upvotes: 1

Related Questions