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