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

【问题】Java线程

dongqing
2017/1/16镜像同步48 回复
碰到了一个问题,先亮代码 public class ThreadTest extends Thread { private boolean run = true; @Override public void run() { while (run) { System.out.println("running");//此行注掉 } System.out.println("run end"); } public static void main(String[] args) throws InterruptedException { ThreadTest t = new ThreadTest(); t.start(); Thread.sleep(1000); t.run = false; } } 代码如上,程序能正常结束,如果将所示行注释掉,程序无法正常结束,为什么啊?如果将run设为volatile变量,能够正常结束,但是为什么空的while循环程序不能正常结束呢?求大神解惑啊@nuanyangyang
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
dongqing机器人#1 · 2017/1/16
我手打的markdown代码高亮标记竟然没起作用
nuanyangyang机器人#2 · 2017/1/16
只有volatile的变量才可以作为线程间同步的机制来使用。从概念上说,如果没有volatile,main里面的写操作和run里面的读操作之间不存在happens-before关系,因此Java不保证那个读操作一定能看到那个写操作写入的值。简单地说,如果不加volatile,也没有锁以及其它同步机制,Java可以让一个线程永远读到旧的值而看不到另一个线程写进去的新值。 多线程永远是个高级话题。即使你这个小小的程序也不简单。建议跟着这个教程 http://docs.oracle.com/javase/tutorial/essential/concurrency/ 系统地学一学,要特别留意happens-before这个词。
suweiquan机器人#3 · 2017/1/16
不知道对不对,我来说说我的看法哈,不对的坐等大神更正。我debug了一下,单纯的while(true){}语句块,事实上并没有不断在跑,而是suspend:all状态的,所以普通的boolean变量run,while并没有进行第二次检测,所以也就是一直运行状态了。然后volatile变量是对所有线程可见的,所以当volatile变量run变为false时,运行就停止了。这只是我的猜测哈
nuanyangyang机器人#4 · 2017/1/16
【 在 suweiquan 的大作中提到: 】 : 不知道对不对,我来说说我的看法哈,不对的坐等大神更正。我debug了一下,单纯的while(true){}语句块,事实上并没有不断在跑,而是suspend:all状态的,所以普通的boolean变量run,while并没有进行第二次检测,所以也就是一直运行状态了。然后volatile变量是对所有线程可见的,所以当volatile变量run变为false时,运行就停止了。这只是我的猜测哈 其实Java是用共享内存模型,所有的类成员变量,不管是不是volatile的,都是所有线程都可见的;关键是不同的线程会看见什么值。这个必须用java memory model仔细地去推理。一般来说,“正确同步”的程序要求对每个变量的每一对读、写操作,以及每一对写、写操作,都有happen-before关系,这时候,读操作会读到根据happen-before关系的“最新的”一个写操作写入的值。如果有一对读、写操作,或者两个写操作,之间没有happen-before关系,那么程序就是不正确的,这种情况下行为就会很诡异了,有可能读到某些意想不到的值。
suweiquan机器人#5 · 2017/1/16
【 在 nuanyangyang 的大作中提到: 】 : : 其实Java是用共享内存模型,所有的类成员变量,不管是不是volatile的,都是所有线程都可见的;关键是不同的线程会看见什么值。这个必须用java memory model仔细地去推理。一般来说,“正确同步”的程序要求对每个变量的每一对读、写操作,以及每一对写、写操作,都有happen-before关系,这时候,读操作会读到根据happen-before关系的“最新的”一个写操作写入的值。如果有一对读、写操作,或者两个写操作,之间没有happen-before关系,那么程序就是不正确的,这种情况下行为就会很诡异了,有可能读到某些意想不到的值。 java共享内存不是只是共享进程的内存吗?但是每个线程应该还是会有线程自己的工作内存的,一般普通变量,线程工作都是会把公共的先读到私有的再操作的。所以我猜测的是由于缺乏了同步,而线程又阻塞了,没有进入第二次检测,自然就没有第二次读入boolean变量run了,所以boolean改变了之后,线程的boolean状态跟进程的并不一样。当然只是猜测哈
nuanyangyang机器人#6 · 2017/1/16
你说的是Java 1.0到1.4的模型。Java 1.5已经舍弃了“工作内存”和“全局内存”的概念了。所以,现在已经没有“工作内存”了,读写之间的可见性全靠happens-before关系来决定。 【 在 suweiquan 的大作中提到: 】 : java共享内存不是只是共享进程的内存吗?但是每个线程应该还是会有线程自己的工作内存的,一般普通变量,线程工作都是会把公共的先读到私有的再操作的。所以我猜测的是由于缺乏了同步,而线程又阻塞了,没有进入第二次检测,自然就没有第二次读入boolean变量run了,所以boolean改变了之后,线程的boolean状态跟进程的并不一样。当然只是猜测哈
suweiquan机器人#7 · 2017/1/16
【 在 nuanyangyang 的大作中提到: 】 : 你说的是Java 1.0到1.4的模型。Java 1.5已经舍弃了“工作内存”和“全局内存”的概念了。所以,现在已经没有“工作内存”了,读写之间的可见性全靠happens-before关系来决定。 : 噢,这样吗,学习了
byzwl机器人#8 · 2017/1/17
可以看看以前暖神的帖子 https://bbs.byr.cn/#!article/Java/39220 【 在 dongqing 的大作中提到: 】 : 配到了一个问题,先量代码 : ``` : public class ThreadTest extends Thread { : ...................
a206206机器人#9 · 2017/1/17
跟有没有注释掉没关系。允许不同程度的优化。只有加上volatile的修饰才是最保险的。 http://stackoverflow.com/questions/38392673/to-force-cancel-asynctask-shouldnt-the-flag-periodically-checked-in-doinbackgro/38519093#38519093