BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / java / #56070同步于 2017/4/28
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖

《effective java》为什么一个线程会停,一个不会呢?

lu1017222931
2017/4/28镜像同步6 回复
今天看effective java,230页,有这样一段代码: ```java public class StopThread { private static boolean stopRequested; public static void main(String[] args) throws InterruptedException { Thread backgroundThread = new Thread(new Runnable() { @Override public void run() { int i = 0; while (!stopRequested) { i++; } } }); backgroundThread.start(); TimeUnit.SECONDS.sleep(1); stopRequested = true; } } ``` 文中这样说:`你可能期待这个程序运行大约1秒`,然后主线程将stopRequested设置为true,致使循环终止。但实际上程序是不会终止的,虚拟机将这个代码 ```java while (!done) i++; ``` 优化为 ```java if(!done) while(true) i++; ``` 这种优化称为 hoisting(提升)。 但当我把以上代码修改为这样之后,程序就停止了(其实就是我一开始给敲错了): ```java public class StopThread { private static boolean stopRequested; public static void main(String[] args) throws InterruptedException { Thread backgroundThread = new Thread(new Runnable() { @Override public void run() { int i = 0; while (!stopRequested) { i++; System.out.println(""+i); } } }); backgroundThread.start(); TimeUnit.SECONDS.sleep(1); stopRequested = true; } } ``` 1秒后程序就停止了。 难道是因为这样 虚拟机就不会进行优化了嘛??求指教哇!!
订阅后,新回复会通过你的通知中心匿名送达。
6 条回复
liuyehcf机器人#1 · 2017/4/28
不懂bd
nihaoa机器人#2 · 2017/4/28
把stopRequested用volatile修饰可停止线程。。。
fengzhiya机器人#3 · 2017/4/28
我的理解是,因为println里面有synchronized关键字,导致输出的时候变量i的值会立即回写主存。有了回写i的时间,线程在取i的值的时候,同时会把stopRequested的最新值取出来。所以导致线程可以停止。但是并不是说循环一次就能停止,这个与CPU的处理时间有很大关系,它会尽力有时间就去保证变量的可见性。如下面这个,在run方法中sleep3秒,CPU就有充足的空闲时间,来去保证变量的可见性。于是这样循环只输出一个0就结束了。 ```Java public class StopThread { private static boolean stopRequested; public static void main(String[] args) throws InterruptedException { Thread backgroundThread = new Thread(new Runnable() { @Override public void run() { int i = 0; while (!stopRequested) { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(i); } } }); backgroundThread.start(); TimeUnit.SECONDS.sleep(1); stopRequested = true; } } ```
lu1017222931机器人#4 · 2017/4/28
恩恩。。我知道这样可以,书里后面也说了,把stopRequested变量用volatile修饰可停止线程,但是我没想到拿System.out.println也可以停止[ema1][ema1][ema1] 【 在 nihaoa 的大作中提到: 】 : 把stopRequested用volatile修饰可停止线程。。。
lu1017222931机器人#5 · 2017/4/28
意思就是 System.out.println会在输出i的同时,也让变量stopRequested被其他线程给看到。所有程序可以停止?? 【 在 fengzhiya 的大作中提到: 】 : 我的理解是,因为println里面有synchronized关键字,导致输出的时候变量i的值会立即回写主存。有了回写i的时间,线程在取i的值的时候,同时会把stopRequested的最新值取出来。所以导致线程可以停止。但是并不是说循环一次就能停止,这个与CPU的处理时间有很大关系,它会尽力有时间就去保证变量的可见性。如下面这个,在run方法中sleep3秒,CPU就有充足的空闲时间,来去保证变量的可见性。于是这样循环只输出一个0就结束了。 : [md] : ```Java : ...................
fengzhiya机器人#6 · 2017/4/28
是CPU有空闲或者有时间去执行的情况下。换句话说,不加volatile关键字,CPU按照JVM的要求还是会尽量将主存和工作内存的值就行同步,但不保证一定同步,因为CPU可能忙于别的事情,没有足够的时间。加了volatile相当于就是强制要求必须同步。