Reputation: 531
I am reading Effective Java of J. Bloch, and in concurrency chapter there is one example:
public class Main {
private static boolean stop;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
int i = 0;
while (!stop) {
i++;
}
}).start();
TimeUnit.SECONDS.sleep(1);
stop = true;
}
}
This example shows that without synchronization child thread won't stop, because it can't see changes made by main thread. But if we change code to this:
public class Main {
private static boolean stop;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
while (!stop) {
System.out.println(i);
}
}).start();
TimeUnit.SECONDS.sleep(1);
stop = true;
}
}
application will stop after 1 second. So could someone explain why System.out.println
synchronizes threads unlike the first variant doesn't?
Upvotes: 1
Views: 92
Reputation: 45339
The book explains that this is because of the hoisting compiler optimization that the first code may run forever.
In short, the code:
while (!stop)
i++;
may be changed to:
if (!stop)
while (true)
i++;
This effectively means that the background (second) thread continues running forever, in the first example; but the optimization isn't applicable to the second code. Synchronization is just proposed as one of the ways to avoid that compiler optimization. More information about this optimization can be found on this question and this one.
Upvotes: 3
Reputation: 2981
Actually, the proper solution would be to declare the variable stop as volatile.
Upvotes: 2
Reputation: 10308
Just because your program stops when you test it does not mean it's guaranteed to stop. Your code is broken, but you may get away with it, in part because some CPU architectures (including x86) have a stronger memory model than Java's. On other architectures that Java supports, your program may not stop. This is why thread safety bugs are so insidious. It's very hard to test thread safety, so you just have to know the rules and follow them.
Upvotes: 1