Home > database >  Java Thread Cooperation with Three Threads Prints Extra Numbers
Java Thread Cooperation with Three Threads Prints Extra Numbers

Time:03-05

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?

CodePudding user response:

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