I am trying to print three AP sequences (in increments of 3) by three threads as follows:
1, 4, 7, 10, ...
2, 5, 8, ...
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).
(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)
(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)
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?
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();
}
}