gotchajavaCritical
Why does this go into an infinite loop?
Viewed 0 times
whydoesthisinfiniteloopinto
Problem
I have the following code:
We know he should have writen just
--update
Here's the bytecode:
I'll read about the instructions to try to understand...
public class Tests {
public static void main(String[] args) throws Exception {
int x = 0;
while(x<3) {
x = x++;
System.out.println(x);
}
}
}We know he should have writen just
x++ or x=x+1, but on x = x++ it should first attribute x to itself, and later increment it. Why does x continue with 0 as value?--update
Here's the bytecode:
public class Tests extends java.lang.Object{
public Tests();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_3
4: if_icmpge 22
7: iload_1
8: iinc 1, 1
11: istore_1
12: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
15: iload_1
16: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
19: goto 2
22: return
}I'll read about the instructions to try to understand...
Solution
Note: Originally I posted C# code in this answer for purposes of illustration, since C# allows you to pass
Perhaps if we write out a method to do the equivalent of what
Right? Increment the value passed and return the original value: that's the definition of the postincrement operator.
Now, let's see how this behavior plays out in your example code:
So the order of values assigned to
This might be clearer still if we re-write the above:
Your fixation on the fact that when you replace
So it's clear:
Update: Incidentally, lest you doubt that
The demo calls
Below is an excerpt of the above program's output. Notice the irregular occurrence of both 1s and 0s.
Starting background thread...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1
int parameters by reference with the ref keyword. I've decided to update it with actual legal Java code using the first MutableInt class I found on Google to sort of approximate what ref does in C#. I can't really tell if that helps or hurts the answer. I will say that I personally haven't done all that much Java development; so for all I know there could be much more idiomatic ways to illustrate this point.Perhaps if we write out a method to do the equivalent of what
x++ does it will make this clearer.public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}Right? Increment the value passed and return the original value: that's the definition of the postincrement operator.
Now, let's see how this behavior plays out in your example code:
MutableInt x = new MutableInt();
x = postIncrement(x);postIncrement(x) does what? Increments x, yes. And then returns what x was before the increment. This return value then gets assigned to x.So the order of values assigned to
x is 0, then 1, then 0.This might be clearer still if we re-write the above:
MutableInt x = new MutableInt(); // x is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
x = temp; // Now x is 0 again.Your fixation on the fact that when you replace
x on the left side of the above assignment with y, "you can see that it first increments x, and later attributes it to y" strikes me as confused. It is not x that is being assigned to y; it is the value formerly assigned to x. Really, injecting y makes things no different from the scenario above; we've simply got:MutableInt x = new MutableInt(); // x is 0.
MutableInt y = new MutableInt(); // y is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
y = temp; // y is still 0.So it's clear:
x = x++ effectively does not change the value of x. It always causes x to have the values x0, then x0 + 1, and then x0 again.Update: Incidentally, lest you doubt that
x ever gets assigned to 1 "between" the increment operation and the assignment in the example above, I've thrown together a quick demo to illustrate that this intermediate value does indeed "exist," though it will never be "seen" on the executing thread.The demo calls
x = x++; in a loop while a separate thread continuously prints the value of x to the console.public class Main {
public static volatile int x = 0;
public static void main(String[] args) {
LoopingThread t = new LoopingThread();
System.out.println("Starting background thread...");
t.start();
while (true) {
x = x++;
}
}
}
class LoopingThread extends Thread {
public @Override void run() {
while (true) {
System.out.println(Main.x);
}
}
}Below is an excerpt of the above program's output. Notice the irregular occurrence of both 1s and 0s.
Starting background thread...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1
Code Snippets
public MutableInt postIncrement(MutableInt x) {
int valueBeforeIncrement = x.intValue();
x.add(1);
return new MutableInt(valueBeforeIncrement);
}MutableInt x = new MutableInt();
x = postIncrement(x);MutableInt x = new MutableInt(); // x is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
x = temp; // Now x is 0 again.MutableInt x = new MutableInt(); // x is 0.
MutableInt y = new MutableInt(); // y is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
y = temp; // y is still 0.public class Main {
public static volatile int x = 0;
public static void main(String[] args) {
LoopingThread t = new LoopingThread();
System.out.println("Starting background thread...");
t.start();
while (true) {
x = x++;
}
}
}
class LoopingThread extends Thread {
public @Override void run() {
while (true) {
System.out.println(Main.x);
}
}
}Context
Stack Overflow Q#3831341, score: 362
Revisions (0)
No revisions yet.