I have a program where 3 Threads are trying to print numbers in sequence from 1 to 10. I am using a CountDownLatch
to keep keep a count.
But the program stops just after printing 1.
Note: I am aware that using AtomicInteger
instead of Integer
can work. But I am looking to find out the issue in the current code.
public class Worker implements Runnable {
private int id;
private volatile Integer count;
private CountDownLatch latch;
public Worker(int id, Integer count, CountDownLatch latch) {
this.id = id;
this.count = count;
this.latch = latch;
}
@Override
public void run() {
while (count <= 10) {
synchronized (latch) {
if (count % 3 == id) {
System.out.println("Thread: " + id + ":" + count);
count++;
latch.countDown();
}
}
}
}
}
Main program:
public class ThreadSequence {
private static CountDownLatch latch = new CountDownLatch(10);
private volatile static Integer count = 0;
public static void main(String[] args) {
Thread t1 = new Thread(new Worker(0, count, latch));
Thread t2 = new Thread(new Worker(1, count, latch));
Thread t3 = new Thread(new Worker(2, count, latch));
t1.start();
t2.start();
t3.start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Edited program with AtomicInteger
:
public class ThreadSequence {
private static AtomicInteger atomicInteger = new AtomicInteger(1);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new WorkerThread(0, atomicInteger));
Thread t2 = new Thread(new WorkerThread(1, atomicInteger));
Thread t3 = new Thread(new WorkerThread(2, atomicInteger));
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
System.out.println("Done with main");
}
}
public class WorkerThread implements Runnable {
private int id;
private AtomicInteger atomicInteger;
public WorkerThread(int id, AtomicInteger atomicInteger) {
this.id = id;
this.atomicInteger = atomicInteger;
}
@Override
public void run() {
while (atomicInteger.get() < 10) {
synchronized (atomicInteger) {
if (atomicInteger.get() % 3 == id) {
System.out.println("Thread:" + id + " = " + atomicInteger);
atomicInteger.incrementAndGet();
}
}
}
}
}
But the program stops just after printing 1.
No this is not what happens. None of the threads terminate.
You have a own count
field in every worker. Other threads do not write to this field.
Therefore there is only one thread, where if (count % 3 == id) {
yields true
, which is the one with id = 0
. Also this is the only thread that ever modifies the count
field and modifying it causes (count % 3 == id)
to yield false
in subsequent loop iterations, causing an infinite loop in all 3 threads.
Change count
to static
to fix this.
Edit
In contrast to Integer
AtomicInteger
is mutable. It is a class that holds a int
value that can be modified. Using Integer
every modification of the field replaces it's value, but using AtomicInteger
you only modify the value inside the AtomicInteger
object, but all 3 threads continue using the same AtomicInteger
instance.