I'm wondering about result of unsafe decrementing/incrementing in java threads, so there is my program:
Main class:
public class Start {
public static void main(String[] args) {
int count = 10000000, pos = 0, neg = 0, zero = 0;
for (int x=0; x<10000; x++) {
Magic.counter = 0;
Thread dec = new Thread(new Magic(false, count));
Thread inc = new Thread(new Magic(true, count));
dec.start();
inc.start();
try {
inc.join();
dec.join();
} catch (InterruptedException e) {
System.out.println("Error");
}
if (Magic.counter == 0)
zero++;
else if (Magic.counter > 0)
pos++;
else
neg++;
}
System.out.println(Integer.toString(neg) + "\t\t\t" + Integer.toString(pos) + "\t\t\t" + Integer.toString(zero));
}
}
Threads class:
public class Magic implements Runnable {
public static int counter = 0;
private boolean inc;
private int countTo;
public Magic(boolean inc, int countTo) {
this.inc = inc;
this.countTo = countTo;
}
@Override
public void run() {
for (int i=0;i<this.countTo;i++) {
if (this.inc)
Magic.counter++;
else
Magic.counter--;
}
}
}
I have run program few times, and always getting much more positive result then negative. I have also tried to change order of which threads starts but this changed nothing. Some results:
Number of results < 0 | Number of results > 0 | Number of results = 0
1103 8893 4
3159 6838 3
2639 7359 2
3240 6755 5
3264 6728 8
2883 7112 5
2973 7021 6
3123 6873 4
2882 7113 5
3098 6896 6
I bet you will see the exact opposite behavior with the following change (that is, reverse the branches without changing anything else):
if (this.inc)
Magic.counter--; // note change, and lie about `this.inc`
else
Magic.counter++;
If true, what might this indicate about this indicate about the thread interactions?
Now, for fun, make Magic.counter
volatile -- [how] do the results change?
What about removing volatile
and surrounding the if/else
with a lock
? (A lock
ensures a full memory-fence and establishes a critical region. It should always yield perfect results.)
Happy coding.
Things to consider:
Magic.counter
variable. (I believe a conforming JVM could actually yield far worse results...)++
and --
operators are inherently non-atomic.