volatile 据说是 实现 可见 非互斥的行为下面是书上的一个例子 。。public class Testvolatile { private static boolean flag ;
public static void main(String []str) throws InterruptedException
{
Thread back = new Thread(new Runnable()
{
public void run(){
int i = 0;
while(!flag)
System.out.println(i++);
}
}) ;
back.start();
Thread.sleep(1000);
flag = true;
}
}
理论上 应该这个程序一直执行下去 , 因为 主线程修改了flag = true 。但是 线程back应该看不到 。。要把flag 设置为volatile 才可以看到 但是我运行了 这个程序 ,发现不需要volatile 的关键字 ,程序依然会停止 。
何解???
public static void main(String []str) throws InterruptedException
{
Thread back = new Thread(new Runnable()
{
public void run(){
int i = 0;
while(!flag)
System.out.println(i++);
}
}) ;
back.start();
Thread.sleep(1000);
flag = true;
}
}
理论上 应该这个程序一直执行下去 , 因为 主线程修改了flag = true 。但是 线程back应该看不到 。。要把flag 设置为volatile 才可以看到 但是我运行了 这个程序 ,发现不需要volatile 的关键字 ,程序依然会停止 。
何解???
解决方案 »
- 求RCP导出成安装程序的方法
- 要達道里面代碼的功能,不用java 2d 有沒有別的思路? 思路就行~
- 关于JUnit使用的一点心得
- 生产者与消费者(线程问题)
- Java里面有通用数据类型吗?
- 关于用JAVA 做线路展现问题(难)
- 救救我!****急切想获取一些SNMP的资源*******
- hibernate 能实现同时更新与查询吗
- 有个模式对话框,如何象VC那样向其发送一个消息,就可模拟用户单击了“确定”按钮
- java ftp上传zip文件
- XML节点内容追加怎么实现?将<a>xx</a>变成<a>xxyyyyy</a>,不要setText('xx'+'yyyyy')?
- Java自定义事件 监听者模式
System.out.println(i++); ;因为默认的flag是false,所以必然会执行打印那句代码,当执行了一会(差不多过了1秒,此时已打印了n行,计算机速度好快\(^o^)/~),cpu转而接着执行主线程flag = true;,此时主线程结束,子线程因为flag=true了也执行结束....
所以就这样,根本无需volatile方法程序自动结束,归根到底是你本身测试方法写的有问题
您书上的例子一定是运行在sever版本上,而您自己的测试版本在client上。
client版的实现没有作优化(hoisting)所以没有永不跳出循环的问题。ps:您可以System.out.println(System.getProperty("java.vm.name"));察看当前VM版本。
if(!flag)
while(true)
i++;
Bloch也只是说这是‘quite acceptable’:)
这个例子说明了什么呢? 我到现在也不清楚volatile的意思是可见的 意思就是说一个线程改变了这个值 别的线程"立马"就能看的到
你不加这个关键字 那么一个线程改变了这个值 别的线程"不能立马"就能看的到 也有可能一秒或者几百年才看的到 也就是说第一个线程改变了值 另外一个线程读取到的可能还是旧的数据
我的回答是 : 一定看的到新的值 只是看到这个新值的时间是1秒还是100年 因素有很多难道你在一边写完一个变量 再访问的时候难道永远看不到 那java完了 彻底完了 我不用编程了 我死了算了5楼说的研究过头了吧 这根VM有关系吗? 这又让我想死了
这里是指volatile 的用法 。。在core java里面 是这样说的。。volatile 关键字为实例域的同步访问提高了一种免锁机制。如果声明一个域为volatile 那么编译器和虚拟机就知道该域是可能被另一个线程并发更新的。(换句话是不是应该理解为 如果不用volatile 那么编译器就不知道他会被另一个线程并发更新,或者是不能立刻知道,否则用volatile 这个有什么必要。)
这个flag加volatile 2个线程才能同步到新值
不加volatile那就不应该同步到新值了 你要问的是不是这个???????如果是 你这里有2个线程同时访问同一个变量flag , 一个是修改 一个是读取
你子线程先执行读取flag操作 一直读取一直打印 后来主线程flag=true设置了新值 那么子线程就应该获取到flag的新值true 只是时间问题(这个时间问题后面再说)
你前面说的 一边写变量 另外访问可以看到 ,这个 是在一个线程内 理论上是这样的。 而且我们大多数都是一个线程内用到的。多线程的时候如果同步了,也是可以看到的
你意思就是说不同步了 那么就获取不到新值了吗? 那是错的 , 你就算不同步 也能获取到新值 你2个线程访问的都是同一个flag
我转一段话给你
Java的内存模型分为主存储区和工作存储区。主存储区保存了Java中所有的实例。也就是说,在我们使用new来建立一个对象后,这个对象及它内部的方法、变量等都保存在这一区域,在MyThread类中的n就保存在这个区域。主存储区可以被所有线程共享。而工作存储区就是我们前面所讲的线程栈,在这个区域里保存了在run方法以及run方法所调用的方法中定义的变量,也就是方法变量。在线程要修改主存储区中的变量时,并不是直接修改这些变量,而是将它们先复制到当前线程的工作存储区,在修改完后,再将这个变量值覆盖主存储区的相应的变量值。----这里就有时间差异了,你这个例子这个时间差异是很小 你另外写一个例子建立几百个线程应该可以看的到时间差异了加volatile关键字使用同步的意思是什么呢? 就是为了让你在1个线程改变了值 其他线程获取到当前变量的新值的时候是"立马"获取到 同理 你自己去加同步锁也是一样的 也就是说让这2个线程共享同一个内存视图 一端改变 另外一端"立马"获取到
Volatile 比同步更简单,只适合于控制对基本变量(整数、布尔变量等)的单个实例的访问。当一个变量被声明成 volatile,任何对该变量的写操作都会绕过高速缓存,直接写入主内存,而任何对该变量的读取也都绕过高速缓存,直接取自主内存。这表示所有线程在任何时候看到的 volatile 变量值都相同。
我看了一下java的内存模型 , 应该是线程运行的时候 会清空线程内存 ,把主内存最新的数据读取出来。。那么如果是主要 ,子线程就应该能读到 flag的值。 只是可能不是立刻而已 。但对于这个程序没有影响。感谢楼上几位兄弟的解释 这里我只是疑问Volatile 这个修饰的作用而已这样看来 Volatile 这个经典的例子事实上没什么意义了 。就是在dcl里面 在java5之后用他可以避免出错了。关键是effective java 和 java core 两本权威的书的解释Volatile 这样看来都是错误的
特别是effective java 里面写到 不用Volatile ,他的机器将会永远执行下去 。就是上面的这个例子我一直不理解呀 ,难道真的是 他搞错了 ,他既然说他的机器运行下去,难道没测试过,为什么他测试 就会这样呢??