How to ensure execution order of threads

Viewed 372

This is a simplified version of the problem. Given n number of threads, each printing a constant number all the time. For example, Thread-1 should always print 1, Thread-2 should always print 2 and so on...

How to ensure, the threads are executed in order i.e. the output should be as below:

Thread-1: 1
Thread-2: 2
Thread-3: 3
.
.
.
Thread-n: n

I have a naïve solution to do it through wait()/notify() but I guess there might be a better solution than that. Perhaps, using Semaphore maybe? I don't know.

Update:

Based on the answers received, I think I was not very clear. There are some constraints:

  1. All threads should start at once (assume we don't really have control on that)
  2. Once all the threads start, there should be some sort of communication between the threads to execute in order.
3 Answers

This sequentially execution of thread can be handled beautifully using Thread.join() method. To handle it properly, you may have to create MyRunnable(or, use any name you prefer) which implements Runnable interface. Inside MyRunnable, you can inject a parent Thread, and call parent.join() at top of MyRunnable.run() method. The code is given below:

public class SequentialThreadsTest {

    static class MyRunnable implements Runnable {
        static int objCount; // to keep count of sequential object

        private int objNum;
        private Thread parent; // keep track of parent thread
        
        MyRunnable(Thread parent) {
            this.parent = parent;
            this.objNum = objCount + 1;
            objCount += 1;
        }

        @Override
        public void run() {
            try {
                if(parent != null) {
                    parent.join();
                }
                System.out.println("Thread-" + objNum + ": " + objNum);

            } catch(InterruptedException e) {
                e.printStackTrace();
                // do something else

            } finally {
                // do what you need to do when thread execution is finished
            }
        }
    }

    public static void main(String[] args) {
        int n = 10;
        
        Thread parentThread = null;

        for(int i=0; i<n; i++) {
            Thread thread = new Thread(new MyRunnable(parentThread));
            thread.start();

            parentThread = thread;
        }
    }
}

And the output is:

Thread-1: 1
Thread-2: 2
Thread-3: 3
Thread-4: 4
Thread-5: 5
Thread-6: 6
Thread-7: 7
Thread-8: 8
Thread-9: 9
Thread-10: 10

You haven't specified many details, but if you only want serializable thread execution you can wait for previous thread to finish and then print. Something like this:

public static void main(String[] args) {
        Thread thread = null;
        for (int i = 0; i < 10; i++) {
            int index = i;
            Thread previousThread = thread;
            thread = new Thread(() -> {
                if (previousThread != null) {
                    try {
                        previousThread.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(index);
            });
            thread.start();
        }
    }

Try making a queue - this will do exactly what you want. Simply change the value of n to however many threads you have, and add all the threads sequentially (only once). If ever you want to stop the threads from executing, all you have to do is add end to the queue. Obviously, for a larger project, you will need to modify this code a little bit (I would recommend replacing the main method with a class initializer and pass the LinkedBlockingQueue as a pre-built argument)

import java.util.concurrent.LinkedBlockingQueue;



public class HelloWorld{
    
    private static int n = 2;
    private static LinkedBlockingQueue<Thread> queue = new LinkedBlockingQueue<>(n+1);
    
    static Thread a = new Thread(()->{
            System.out.print("a");
        
        });
        
    static Thread b = new Thread(()->{
            System.out.print("b");
        
        });    
        
    static Thread end = new Thread(()->{
            break_ = true;
        
        }); 


    
    public static final int END = 20;//this and the counter are just here so the code doesn't run forever
    public static volatile int i = 0;
    public static volatile boolean break_ = false;
    public static void main(String []args){
        
        queue.add(a);
        queue.add(b);
        //queue.add(end);
        
        
        outerloop:
        while(true){
            
            Thread toBeRun = queue.poll();
            try{
                toBeRun.run();
                queue.add(toBeRun);
                i++;
                if(i>=END || break_){//i>=END does not need to be here, it's just to stop it from running forever in this example
                    break;
                }
            }catch(NullPointerException e){
                break;
            }
            
            
            
            
        }
        
     }
}

Note: This uses java 8 lambdas. If you're using an older version of java, you will need to create the threads using the run method.

Related