effective java 中第66条代码运行结果与书本不一致

本文探讨了Effective Java一书中关于线程停止的示例代码在不同JVM模式下的行为差异,尤其是在server模式下因JVM优化导致的死锁现象,并提出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

effective java 书中66条中的这段代码:

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修饰符不执行互斥访问,但是它可以保证任何一个线程在读取该域的时候可以读取到最近被写入的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值