https://stackoverflow.com/questions/64821070/print-a-sequence-of-numbers-using-threads-without-any-synchronization

https://medium.com/@das.subhankar90/java-program-for-printing-sequence-using-3-threads-5ffb2dd56bee

Method-1: Using Conditional Queues

class PrintSequenceWorker implements Runnable {
 
    private final int remainder;
    private final int maxNumber;
    private final int numOfThreads;
 
    // keep it static to share between threads
    private static final Object lock = new Object();
 
    // keep it static to share the current number being printed
    // no need for volatile since it is guarded by `lock`
    private static int number = 0;
 
    PrintSequenceWorker(int remainder, int maxNumber, int numOfThreads) {
        this.remainder = remainder;
        this.maxNumber = maxNumber;
        this.numOfThreads = numOfThreads;
    }
 
    @Override
    public void run() {
        synchronized (lock) {
            while (true) {
                while (number % numOfThreads != remainder) {
                    try {
                        // !imp: when number is overshoot then
                        // we must not wait again if lock is held
                        if (number > maxNumber) {
                            break;
                        }
                        lock.wait();
                    } catch (InterruptedException e) {
                        System.out.println(e.getMessage());
                    }
                }
 
                // determine why the loop ended
                // if we overshoot the number then we can stop
                if (number > maxNumber) {
                    break;
                }
 
                System.out.println(Thread.currentThread().getName() + ": " + number);
 
                number++;
 
                lock.notifyAll();
            }
        }
    }
}
  • Driver
public class ConcurrentNumbersSequence {
 
    public static void main(String[] args) throws InterruptedException {
 
        // inputs:
        // * numOfThreads
        // * maxNumberToPrint assuming start happens from 0
        int maxNumberToPrint = 20;
        int numOfThreads = 5;
 
        Thread[] threads = new Thread[numOfThreads];
        for (int i = 0; i < numOfThreads; i++) {
            threads[i] = new Thread(new PrintSequenceWorker(i, maxNumberToPrint, numOfThreads));
            threads[i].start();
        }
 
        // we have created non-daemon threads so the
        // program will continue to execute till all threads die
        // But we can still wait for all the threads to stop explicitly
        for (int i = 0; i < numOfThreads; i++) {
            threads[i].join();
        }
 
        System.out.println("Program ended");
    }
}

Notes

 
number = 21, assuming all the waiting threads have been notified in the previous step. Execution will start from the wait statement:
 
BLOCKED Thread-0
BLOCKED Thread-1 -- suppose this holds the lock
BLOCKED Thread-2
 
// next
 
Thread-1 gets its condition fulfilled (number % 3 == remainder), but due to overshoot we stop execution without incrementing the number (second if-condition)
this breaks while loop, releases the lock and terminates Thread-2
 
BLOCKED Thread-0 -- suppose this will hold the lock next
TERMINATED Thread-1
BLOCKED Thread-2
 
// next
 
Thread-0 will still wait since number was not incremented and the condition will never be fulfilled, hence execution never complete and we reach livelock problem
 
WAITING Thread-0
TERMINATED Thread-1
BLOCKED Thread-2