volatile关键字

蜡笔小新没有小脾气 2017-09-12 02:45:04
import com.sun.corba.se.impl.orb.ParserTable.TestAcceptor1;


public class text {
public static void main(String[] args) {
class ThreadStop extends Thread{

private boolean stoped = false;
@Override
public void run() {
while(!stoped){
try {
System.out.println("11111");
} catch (Exception e) {
e.printStackTrace();
}
}
}
void getStop(){
stoped = true;
}
}
ThreadStop q = new ThreadStop();
q.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
q.getStop();
}
}

为什么在stoped前面加不加volatile关键字是一样的效果
...全文
394 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
引用 2 楼 zs808 的回复:
变量可见性本身就是一个玄学问题,其实效果是不一样的,你的例子没法预测正确的效果,也就无法正确验证volidate语义。 如果想正确验证,把

while(!stoped){
                    try {
                        System.out.println("11111");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
改成

while(!stoped){
                    try {
                        //System.out.println("11111");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
然后再试试加与不加volidate的区别,这时候结果就很清楚了(误
你能给我解释一下,为什么不加System.out.print();就可以验证volatile了吗?我把这句话去掉以后,没添加volatile时,它就一直while循环,加了volatile,他就不循环了,这是为什么
zs808 2017-09-15
  • 打赏
  • 举报
回复
变量可见性本身就是一个玄学问题,其实效果是不一样的,你的例子没法预测正确的效果,也就无法正确验证volidate语义。 如果想正确验证,把

while(!stoped){
                    try {
                        System.out.println("11111");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
改成

while(!stoped){
                    try {
                        //System.out.println("11111");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
然后再试试加与不加volidate的区别,这时候结果就很清楚了(误
zs808 2017-09-15
  • 打赏
  • 举报
回复
引用 5 楼 pilnyun335857183 的回复:
[quote=引用 4 楼 zs808 的回复:] [quote=引用 3 楼 pilnyun335857183 的回复:] 楼上说玄学不知道是什么意思, 玄不抵愚这个倒是听得比较多。 楼主不理解的应该是在两个线程间stoped是怎么同步的,其实这个很简单的,因为jmm会尽力保证内存的一致性。 首先这里有两个东西 工作内存和主内存。工作内存是线程的独有的,而主内存是全局的多个线程中主内存内容才最终有效。 而多个工作内存与主内存之间 jmm是提供机制保证一致性的,什么时候保证呢?线程空闲的时候(毕竟线程一致占据CPU也没法去更新不是),也就是在线程让出CPU后jmm会尝试将主内存的内容刷新到工作内存中。 那volatile是怎么实现的?很简单 工作内存中不保留volatile变量的副本,每个线程对volatile变量的访问直接访问主内存。volatile的变量问题是不是就很好理解了? 再说楼主的例子,q.getStop();调用后主内存中stoped被更新为true 一旦q线程获取的cpu时间片结束线程挂起 jmm更新q的工作内存 q再次获取到CPU时间片后!stoped判断为false循环也就跳出来了。 楼主试试在while循环中加入Thread.sleep();因为sleep会让主动线程结束当前CPU时间片的占用。
不经大脑考虑就给别人套帽子,只能暴漏你的肤浅与无知。一味套用书本上的那些知识,只能成为井底之蛙。 关于你说的“Sleep释放时间片”请移步 http://bbs.csdn.net/topics/392264076。你试着在System.out.println("------------------");前后加Sleep,去“释放时间片”试试。 关于玄学问题,JVM对于时间片调度,受操作系统跟CPU架构等等多个因素影响,在楼主的例子中,一个变量在何时被另外一个线程看到,没法预估。会输出多少个"11111",也是无法计算出来的,这是我说的玄学问题。 volidate保证内存语义,从宏观上来说,确实是你说的那样,但是volidate同样会影响JIT的操作流程。我给的例子,就是说明这一点,你不明白,非要去套Thread.sleep()与时间片调度,在明白人眼里,不是很好笑么? 还是那句话,静下心来讨论问题,不要上来给别人套“玄不抵愚”的帽子,探索书本以外的知识,你会发现另一片天空。[/quote] 首先,我以为你是一个跑到技术区来算命的家伙 毕竟搞技术的我没见过开口讲玄学的 这个我先表示抱歉。 至于我的回答无论在是宏观上还是事实上都是如此吧;jit优化确实会将循环中使用的变量直接从工作内存中读取直到循环结束,但是jmm的同步机制就不起作用了?并不是吧,就如你另外一篇帖子里面的例子, while (true) { if (td.isFlag()) { System.out.println("------------------"); break; }else{ try { Thread.sleep(0); } catch (InterruptedException e) { e.printStackTrace(); } } } 这是我加的的Thread.sleep 你自己有加过吗? ------------------ flag=true 是我这边得到过的唯一结果(标准输入输出无延迟)。我可没有纠结于线程调度,那只是多线程运转的的机制而已。 至于volatile jit会将多个线程之间共享的volatile变量优化到线程循环中只读工作内存?同样你可以在那个例子里对flag加volatile来验证。 程序是由人按一定的逻辑去实现的,那按照这些逻辑自然可以去推论程序的运行;这边楼主的问题了解了jmm内存同步的机制,不就可以理解程序的运行结果了?当然在jvm中还有更多的知识要求了解。 最后强调下jmm的内存同步是一种弱同步,多线程下要保证线程按期望执行还是要靠额外的逻辑去实现的 加volatile 加cas逻辑实现 加锁这就要看具体情况了。[/quote] 随便你怎么去理解吧,既然不能静下心来去讨论问题,也没有交流的必要了。
pilnyun335857183 2017-09-15
  • 打赏
  • 举报
回复
引用 4 楼 zs808 的回复:
[quote=引用 3 楼 pilnyun335857183 的回复:] 楼上说玄学不知道是什么意思, 玄不抵愚这个倒是听得比较多。 楼主不理解的应该是在两个线程间stoped是怎么同步的,其实这个很简单的,因为jmm会尽力保证内存的一致性。 首先这里有两个东西 工作内存和主内存。工作内存是线程的独有的,而主内存是全局的多个线程中主内存内容才最终有效。 而多个工作内存与主内存之间 jmm是提供机制保证一致性的,什么时候保证呢?线程空闲的时候(毕竟线程一致占据CPU也没法去更新不是),也就是在线程让出CPU后jmm会尝试将主内存的内容刷新到工作内存中。 那volatile是怎么实现的?很简单 工作内存中不保留volatile变量的副本,每个线程对volatile变量的访问直接访问主内存。volatile的变量问题是不是就很好理解了? 再说楼主的例子,q.getStop();调用后主内存中stoped被更新为true 一旦q线程获取的cpu时间片结束线程挂起 jmm更新q的工作内存 q再次获取到CPU时间片后!stoped判断为false循环也就跳出来了。 楼主试试在while循环中加入Thread.sleep();因为sleep会让主动线程结束当前CPU时间片的占用。
不经大脑考虑就给别人套帽子,只能暴漏你的肤浅与无知。一味套用书本上的那些知识,只能成为井底之蛙。 关于你说的“Sleep释放时间片”请移步 http://bbs.csdn.net/topics/392264076。你试着在System.out.println("------------------");前后加Sleep,去“释放时间片”试试。 关于玄学问题,JVM对于时间片调度,受操作系统跟CPU架构等等多个因素影响,在楼主的例子中,一个变量在何时被另外一个线程看到,没法预估。会输出多少个"11111",也是无法计算出来的,这是我说的玄学问题。 volidate保证内存语义,从宏观上来说,确实是你说的那样,但是volidate同样会影响JIT的操作流程。我给的例子,就是说明这一点,你不明白,非要去套Thread.sleep()与时间片调度,在明白人眼里,不是很好笑么? 还是那句话,静下心来讨论问题,不要上来给别人套“玄不抵愚”的帽子,探索书本以外的知识,你会发现另一片天空。[/quote] 首先,我以为你是一个跑到技术区来算命的家伙 毕竟搞技术的我没见过开口讲玄学的 这个我先表示抱歉。 至于我的回答无论在是宏观上还是事实上都是如此吧;jit优化确实会将循环中使用的变量直接从工作内存中读取直到循环结束,但是jmm的同步机制就不起作用了?并不是吧,就如你另外一篇帖子里面的例子, while (true) { if (td.isFlag()) { System.out.println("------------------"); break; }else{ try { Thread.sleep(0); } catch (InterruptedException e) { e.printStackTrace(); } } } 这是我加的的Thread.sleep 你自己有加过吗? ------------------ flag=true 是我这边得到过的唯一结果(标准输入输出无延迟)。我可没有纠结于线程调度,那只是多线程运转的的机制而已。 至于volatile jit会将多个线程之间共享的volatile变量优化到线程循环中只读工作内存?同样你可以在那个例子里对flag加volatile来验证。 程序是由人按一定的逻辑去实现的,那按照这些逻辑自然可以去推论程序的运行;这边楼主的问题了解了jmm内存同步的机制,不就可以理解程序的运行结果了?当然在jvm中还有更多的知识要求了解。 最后强调下jmm的内存同步是一种弱同步,多线程下要保证线程按期望执行还是要靠额外的逻辑去实现的 加volatile 加cas逻辑实现 加锁这就要看具体情况了。
zs808 2017-09-15
  • 打赏
  • 举报
回复
引用 3 楼 pilnyun335857183 的回复:
楼上说玄学不知道是什么意思, 玄不抵愚这个倒是听得比较多。 楼主不理解的应该是在两个线程间stoped是怎么同步的,其实这个很简单的,因为jmm会尽力保证内存的一致性。 首先这里有两个东西 工作内存和主内存。工作内存是线程的独有的,而主内存是全局的多个线程中主内存内容才最终有效。 而多个工作内存与主内存之间 jmm是提供机制保证一致性的,什么时候保证呢?线程空闲的时候(毕竟线程一致占据CPU也没法去更新不是),也就是在线程让出CPU后jmm会尝试将主内存的内容刷新到工作内存中。 那volatile是怎么实现的?很简单 工作内存中不保留volatile变量的副本,每个线程对volatile变量的访问直接访问主内存。volatile的变量问题是不是就很好理解了? 再说楼主的例子,q.getStop();调用后主内存中stoped被更新为true 一旦q线程获取的cpu时间片结束线程挂起 jmm更新q的工作内存 q再次获取到CPU时间片后!stoped判断为false循环也就跳出来了。 楼主试试在while循环中加入Thread.sleep();因为sleep会让主动线程结束当前CPU时间片的占用。
不经大脑考虑就给别人套帽子,只能暴漏你的肤浅与无知。一味套用书本上的那些知识,只能成为井底之蛙。 关于你说的“Sleep释放时间片”请移步 http://bbs.csdn.net/topics/392264076。你试着在System.out.println("------------------");前后加Sleep,去“释放时间片”试试。 关于玄学问题,JVM对于时间片调度,受操作系统跟CPU架构等等多个因素影响,在楼主的例子中,一个变量在何时被另外一个线程看到,没法预估。会输出多少个"11111",也是无法计算出来的,这是我说的玄学问题。 volidate保证内存语义,从宏观上来说,确实是你说的那样,但是volidate同样会影响JIT的操作流程。我给的例子,就是说明这一点,你不明白,非要去套Thread.sleep()与时间片调度,在明白人眼里,不是很好笑么? 还是那句话,静下心来讨论问题,不要上来给别人套“玄不抵愚”的帽子,探索书本以外的知识,你会发现另一片天空。
pilnyun335857183 2017-09-15
  • 打赏
  • 举报
回复
楼上说玄学不知道是什么意思, 玄不抵愚这个倒是听得比较多。 楼主不理解的应该是在两个线程间stoped是怎么同步的,其实这个很简单的,因为jmm会尽力保证内存的一致性。 首先这里有两个东西 工作内存和主内存。工作内存是线程的独有的,而主内存是全局的多个线程中主内存内容才最终有效。 而多个工作内存与主内存之间 jmm是提供机制保证一致性的,什么时候保证呢?线程空闲的时候(毕竟线程一致占据CPU也没法去更新不是),也就是在线程让出CPU后jmm会尝试将主内存的内容刷新到工作内存中。 那volatile是怎么实现的?很简单 工作内存中不保留volatile变量的副本,每个线程对volatile变量的访问直接访问主内存。volatile的变量问题是不是就很好理解了? 再说楼主的例子,q.getStop();调用后主内存中stoped被更新为true 一旦q线程获取的cpu时间片结束线程挂起 jmm更新q的工作内存 q再次获取到CPU时间片后!stoped判断为false循环也就跳出来了。 楼主试试在while循环中加入Thread.sleep();因为sleep会让主动线程结束当前CPU时间片的占用。
teng_sd_cn 2017-09-13
  • 打赏
  • 举报
回复
volatile是为了在多个线程间保证内存可见性。

50,504

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧