举个volatile例子

大海Online 2008-03-20 10:47:43
请举个例子, 不使用 volatile 关键字时, 结果是不稳定的,使用volatile时,结果是不稳定的


不要说明, 只要一段简短的java代码来说明只有使用 volatile 关键字时才能达到预期的目标
...全文
296 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
zenny_chen 2008-03-22
  • 打赏
  • 举报
回复
楼主的样例代码犯了与3楼朋友同一个毛病。
我把三楼的代码再贴一下:

if(i>0)
{
Thread,.sleep(10);
System.out.println(i--);
}


这里很明显无法表现出volatile的功效。因为比如说当前i为1,i>0成立,那么接下去操作。碰到sleep()之后切换线程,i的值很有后可能被其它线程修改,这很正常。

我想说的是,在Java中,volatile很难测试。因为在C/C++中测也不是很容易,还要设置编译选项,开启代码优化才可能发现volatile的功效。
volatile字面意思是“不稳定的,易挥发的”。也就是说其值将受到外部的改变。在C/C++中,由于使用机器的寄存器,所以变量的值将会保存在寄存器中,比如以下代码:

while(i > 0)
{
i--;
}

i的值很有可能被放入寄存器(这里也很有可能被放在循环计数寄存器中),这样在这个循环中,i 所在地址的内容可能不会一下子受到改变,改变的只是寄存器中的值。如果给他加以volatile修饰的话,那么每次做“i--”的时候,总要访问i 的地址,对于内容进行减1操作(尽管这可能会在Cache中)。不过即使是访问Cache,其速度也不会有寄存器那么快。
所以,在目前Java环境下测volatile比较困难,目前的环境也没有提供非常完善的代码调试工具,也就是说不公开Java虚拟机指令集。至少在Eclipse上没有,不知道在NetBeans上怎么样。不过即使要发挥volatile,那么也只能依靠JIT技术了。让Java字节码及时地转为本地机器指令码进行运行,只有这样才有可能看到效果,而且转换后的机器二进制码又要是经过一定优化的,也就是不用volatile修饰的变量尽可能的使用寄存器。
所以楼主也不要怪二楼、三楼,先不看你的测试代码,本身的测试环境也是有限的。
大海Online 2008-03-22
  • 打赏
  • 举报
回复
UP!!!
minl 2008-03-21
  • 打赏
  • 举报
回复
public class Counter_ThreadSafe {
public int getCount(){
return _count;
}
public synchronized void count(){
++_count;
}
private volatile int _count=0;
}

////由此不同线程调用每次调用getCount() 都会得到正确计数值。
////不过这个例子似乎不是很好。因为必须对count加synchronized
大海Online 2008-03-21
  • 打赏
  • 举报
回复
请举个例子, 不使用 volatile 关键字时, 结果是不稳定的,使用volatile时,结果是稳定的

使用volatile时,结果是稳定的, 发贴时写成不稳定了, 不好意思, ```当时太急了``
大海Online 2008-03-21
  • 打赏
  • 举报
回复
通过测试二楼的代码, 发现结果很不稳定, 与没有volatile修饰符结果是一样的,

代码如下:

import java.util.Random;

public class Counter_ThreadSafe {

public int getCount(){
return _count;
}
public synchronized void count(){
++_count;
}
private volatile int _count=0;

public static void main(String[] args) throws InterruptedException {
final Counter_ThreadSafe c = new Counter_ThreadSafe();
final Random rand = new Random();
for (int i = 0; i < 100; i++) {
Thread.sleep(0);
new Thread(new Runnable() {
public void run() {
try {
c.count();
Thread.sleep(rand.nextInt() % 2 + 2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(c.getCount());
}
}).start();
}
}
}





测试三楼的代码, 加不加volatile 都会有负数的情况发生, 代码如下:

import java.util.Random;

public class Counter_ThreadSafe {

private static volatile int i = 7;

private void count() throws InterruptedException {
if(i>0)
{
Thread.sleep(10);
System.out.println(i--);
}
}

public static void main(String[] args) throws InterruptedException {
final Counter_ThreadSafe c = new Counter_ThreadSafe();
final Random rand = new Random();
for (int i = 0; i < 100; i++) {
Thread.sleep(0);
new Thread(new Runnable() {
public void run() {
try {
c.count();
Thread.sleep(rand.nextInt() % 2 + 2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//System.out.println(c.getCount());
}
}).start();
}
}
}
nihuajie05 2008-03-21
  • 打赏
  • 举报
回复
只接触过一次,是在学习线程安全的Singleton模式的时候学的
刘彬彬 2008-03-21
  • 打赏
  • 举报
回复
这个修饰符应该表示变量是线程安全的吧
你写两个或多个线程,并发访问同一个volatile的变量i
例如在run里面:
if(i>0)
{
Thread,.sleep(10);
System.out.println(i--);
}
如果某个线程的输出为0甚至是负数,则说明你的程序不是线程安全的
但是加了volatile修饰应该就不会有这种情况发生
大海Online 2008-03-21
  • 打赏
  • 举报
回复
大家发表下自己的意见!!!

62,623

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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