I am trying to reproduce Thread Interference scenario .. but something is not right. Please help me understand what
Main
public static void main(String args[]) throws InterruptedException {
Counter c = new Counter();
for (int i = 0; i < 1000000; i++) {
new T1(c).start();
new T2(c).start();
}
System.out.println(c.value()); // <-- Expect this to sometimes not be 0
}
Counter
class Counter {
private int c = 0;
public void increment() { // <-- intentionally not synchronized
c++;
}
public void decrement() { // <-- intentionally not synchronized
c--;
}
public int value() {
return c;
}
}
Thread 1
public class T1 extends Thread {
Counter c;
T1(Counter c) {
this.c = c;
}
public void start() {
c.decrement(); // <-- Decrement
}
}
Thread 2
public class T2 extends Thread {
Counter c;
T2(Counter c) {
this.c = c;
}
public void start() {
c.increment(); // <-- Increment
}
}
As i am starting 1000000 threads each of which is operating on non-synchronized section of code, i would expect some operations to overlap.
Interference happens when two operations, running in different
threads, but acting on the same data, interleave. This means that the
two operations consist of multiple steps, and the sequences of steps
overlap.It might not seem possible for operations on instances of Counter to
interleave, since both operations on c are single, simple statements.
However, even simple statements can translate to multiple steps by the
virtual machine. We won’t examine the specific steps the virtual
machine takes — it is enough to know that the single expression c++
can be decomposed into three steps:Retrieve the current value of c. Increment the retrieved value by 1.
Store the incremented value back in c.
What am i missing please?
As it stands your program is not actually doing anything concurrently, everything is being done in the main thread. Since you override the start method and never call the superclass version, then you are not going to get the functionality to get the new thread running.
But just calling super.start() won’t fix the problem. Consider start is run by the current thread, so even if you manage to start the thread, the increment/decrement will be executed by the thread calling start(), and there is no concurrent access and modification going on.
I’d move the increment/decrement stuff out of the start method (deleting your overridden version of it) and override the run method, putting it there instead. Of course, consider using Runnable instead of Thread next time, with Runnable it’s harder to make this kind of error.