0

I am trying to print three AP sequences (in increments of 3) by three threads as follows:

  • Thread-1 is printing the sequence 1, 4, 7, 10, ...
  • Thread-2 is printing the sequence 2, 5, 8, ...
  • Thread-3 is printing the sequence 3, 6, 9, ...

A thread should wait while any other threads are taking their turns to print a number of their sequence. The threads should cooperate with each other to print the numbers sequentially from 1 to LIMIT (an integer; here LIMIT = 10).

Expected Output

(For LIMIT = 10)

1 (printed by Thread-1)
2 (printed by Thread-2)
3 (printed by Thread-3)
4 (printed by Thread-1)
5 (printed by Thread-2)
6 (printed by Thread-3)
7 (printed by Thread-1)
8 (printed by Thread-2)
9 (printed by Thread-3)
10 (printed by Thread-1)

Actual Output

(For LIMIT = 10)

1 (printed by Thread-1)
2 (printed by Thread-2)
3 (printed by Thread-3)
4 (printed by Thread-1)
5 (printed by Thread-2)
6 (printed by Thread-3)
7 (printed by Thread-1)
8 (printed by Thread-2)
9 (printed by Thread-3)
10 (printed by Thread-1)
11 (printed by Thread-2)
12 (printed by Thread-3)

Code

class PrintingSequences {
    private static final int LIMIT = 10;
    int counter = 1;
    boolean isPrinting = false;

    // prints 1, 4, 7, 10, ...
    synchronized void printAPStartingFrom1() {
        while (counter <= LIMIT) {
            while (isPrinting || counter % 3 != 1) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println(e);
                    Thread.currentThread().interrupt();
                }
            }
            isPrinting = true;
            System.out.println(counter++ + " (printed by " + Thread.currentThread().getName() + ")");
            isPrinting = false;
            notifyAll();
        }
    }

    // prints 2, 5, 8, 11, ...
    synchronized void printAPStartingFrom2() {
        while (counter <= LIMIT) {
            while (isPrinting || counter % 3 != 2) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println(e);
                    Thread.currentThread().interrupt();
                }
            }
            isPrinting = true;
            System.out.println(counter++ + " (printed by " + Thread.currentThread().getName() + ")");
            isPrinting = false;
            notifyAll();
        }
    }

    // prints 3, 6, 9, 12, ...
    synchronized void printAPStartingFrom3() {
        while (counter <= LIMIT) {
            while (isPrinting || counter % 3 != 0) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println(e);
                    Thread.currentThread().interrupt();
                }
            }
            isPrinting = true;
            System.out.println(counter++ + " (printed by " + Thread.currentThread().getName() + ")");
            isPrinting = false;
            notifyAll();
        }
    }
}

public class TripleThreadCommunication {
    public static void main(String[] args) {
        PrintingSequences naturalNumbers = new PrintingSequences();

        new Thread("Thread-1") {
            @Override
            public void run() {
                naturalNumbers.printAPStartingFrom1();
            }
        }.start();

        new Thread("Thread-2") {
            @Override
            public void run() {
                naturalNumbers.printAPStartingFrom2();
            }
        }.start();

        new Thread("Thread-3") {
            @Override
            public void run() {
                naturalNumbers.printAPStartingFrom3();
            }
        }.start();
    }
}

The program has three different synchronized methods: printAPStartingFrom1(), printAPStartingFrom2(), printAPStartingFrom3(), invoked by Thread-1, Thread-2, and Thread-3 respectively. The threads cooperate with each other using wait() and notifyAll() methods.

Why is the output consistently involving two additional numbers which are exceeding the given limit of 10, i.e., 11 and 12?

Akash Das
  • 163
  • 15
  • You omitted the crucial bit... the actual output showing which thread printed which number. – Jim Garrison Mar 02 '22 at 19:58
  • @JimGarrison I have edited the outputs to include the names of the threads – Akash Das Mar 02 '22 at 20:06
  • This seems very painful, and doesn't seem likely to teach you anything. – Nathan Hughes Mar 02 '22 at 20:10
  • @NathanHughes I wanted to use this as a demonstration of inter-thread communication between three threads for the learners. But the unexpected output is baffling me. – Akash Das Mar 02 '22 at 20:14
  • This doesn't seem like a great way of demonstrating inter-thread communication. Maybe try using Actors? – Nathan Hughes Mar 02 '22 at 21:55
  • @NathanHughes I had intended to use this as a demonstration of wait() and notifyAll() methods in a scenario involving three threads. I do understand threads can have unexpected behavior and this is probably not very useful. Just meant it as a proof of concept. – Akash Das Mar 03 '22 at 12:01

1 Answers1

1

When a thread is woken up(wait->runnable), it needs to judge again whether the current counter is less than LIMIT, otherwise, it will continue to print until while (counter <= LIMIT) does not hold.(That's why 11 and 12 are printed too).

I would suggest that you determine in advance how many times each thread will loop(This will make the code simpler):

    // thread1
    // prints 1, 4, 7, 10, ...
    synchronized void printAPStartingFrom1() {
        int count = LIMIT % 3 == 0 ? LIMIT / 3 : LIMIT / 3 + 1;
        for (int i = 0; i < count; i++) {
            while (counter % 3 != 1) {
                wait();
            }
            printAndAddCounter();
            notifyAll();
        }
    }
    // thread2
    // prints 2, 5, 8, 11, ...
    synchronized void printAPStartingFrom1() {
        int count = (LIMIT - 1) % 3 == 0 ? LIMIT / 3 : LIMIT / 3 + 1;
        for (int i = 0; i < count; i++) {
            while (counter % 3 != 2) {
                wait();
            }
            printAndAddCounter();
            notifyAll();
        }
    }
    // thread3
    // prints 3, 6, 9, 12, ...
    synchronized void printAPStartingFrom1() {
        int count = LIMIT / 3;
        for (int i = 0; i < count; i++) {
            while (counter % 3 != 0) {
                wait();
            }
            printAndAddCounter();
            notifyAll();
        }
    }
zysaaa
  • 1,777
  • 2
  • 8
  • 19