effective java 书中66条中的这段代码:
需要在程序执行的时候加上[color=red]-server[/color]参数,即: java -server StopThread 。虚拟机主要分两种模式一种是client模式一种是server模式,在win下默认是client模式。
以上的实验只有在server模式下,才能得到书中的结果。即线程不会退出。
如果这段代码在[color=red]server[/color]模式下执行,线程一直不会结束。因为没有同步stopRequested域,backgroundThread线程的stopRequested域是线程的一个拷贝,不能保证backgroundThread线程何时能"看到"主线程对stopRequested值的修改。并且虚拟机会对代码进行修改,以提升性能。将
修改为
所以这段代码是一个死循环,线程一直得不到结束。
如果是在[color=red]client[/color]模式下,这段代码在backgroundThread开始后一秒左右线程就会结束。可能是主线程对stopRequest值的改变backgroundThread很快就"看到"了并且没有做上述的优化。所以client模式下,一秒后结束。
在server模式中如果把原来的代码改为
执行程序这时1秒后也会结束。可以猜测,添加了 System.out.println("i");代码后,jvm没有再对该段代码进行优化。并且主线程对stopRequest值的改变backgroundThread很快就"看到"了。所以在一秒后线程结束。
所以导致该代码在server模式下会死循环,主要是因为jvm对while部分的代码进行优化,在该程序中其实主线程对stopRequest的改变backgroundThread很快就看了。但是jvm并不保证backgroundThread线程能及时看到主线程对stopRequested值的修改。如果需要保证及时看到,可以给域加上volitile修饰。
volatile修饰符不执行互斥访问,但是它可以保证任何一个线程在读取该域的时候可以读取到最近被写入的值。
import java.util.concurrent.*;
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;
}
}
需要在程序执行的时候加上[color=red]-server[/color]参数,即: java -server StopThread 。虚拟机主要分两种模式一种是client模式一种是server模式,在win下默认是client模式。
以上的实验只有在server模式下,才能得到书中的结果。即线程不会退出。
如果这段代码在[color=red]server[/color]模式下执行,线程一直不会结束。因为没有同步stopRequested域,backgroundThread线程的stopRequested域是线程的一个拷贝,不能保证backgroundThread线程何时能"看到"主线程对stopRequested值的修改。并且虚拟机会对代码进行修改,以提升性能。将
while (!stopRequested)
i++;
修改为
if(!stopRequested)
while(true)
i++;
所以这段代码是一个死循环,线程一直得不到结束。
如果是在[color=red]client[/color]模式下,这段代码在backgroundThread开始后一秒左右线程就会结束。可能是主线程对stopRequest值的改变backgroundThread很快就"看到"了并且没有做上述的优化。所以client模式下,一秒后结束。
在server模式中如果把原来的代码改为
while(!stopRequested){
i++; System.out.println("i");
}
执行程序这时1秒后也会结束。可以猜测,添加了 System.out.println("i");代码后,jvm没有再对该段代码进行优化。并且主线程对stopRequest值的改变backgroundThread很快就"看到"了。所以在一秒后线程结束。
所以导致该代码在server模式下会死循环,主要是因为jvm对while部分的代码进行优化,在该程序中其实主线程对stopRequest的改变backgroundThread很快就看了。但是jvm并不保证backgroundThread线程能及时看到主线程对stopRequested值的修改。如果需要保证及时看到,可以给域加上volitile修饰。
volatile修饰符不执行互斥访问,但是它可以保证任何一个线程在读取该域的时候可以读取到最近被写入的值。