In the "Effective Java" book:
// Broken! - How long would you expect this program to run?
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested)
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
the backgroundThread will not stop after one second. Because hoisting, the optimization in JVM, HotSpot server VM does.
You can view this in the following topic:
Why HotSpot will optimize the following using hoisting?.
The optimization goes like this:
if (!done)
while (true)
i++;
there are two ways to fix the problem.
1. Use volatile
private static volatile boolean stopRequested;
The function of volatile is
- forbid hoisting
- it guarantees that any thread that reads the field will see the most recently written value
2. Use synchronized
public class StopThread {
private static boolean stopRequested;
private static synchronized void requestStop() {
stopRequested = true;
}
private static synchronized boolean stopRequested() {
return stopRequested;
}
public static void main(String[] args)
throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested())
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop();
}
}
The above code is right in the Effective Java book, its equivalent that use volatile
to decorate the stopRequested
.
private static boolean stopRequested() {
return stopRequested;
}
If this method omit the synchronized
keyword, this program isn't working well.
I think that this change cause the hoisting when the method omit the synchronized
keyword.
Is that right?