为什么我的volatile关键字没有体现出变量的可见性?
public class TestVol {
public volatile static int i=0;
public static void main(String[] args) throws InterruptedException {
System.out.println(TestVol.i);
Thread t1=new Thread(new Task(TestVol.i));
Thread t2=new Thread(new Task(TestVol.i));
t1.start();
t2.start();
System.out.println(TestVol.i);
Thread.sleep(12000);
System.out.println(TestVol.i);
}
}
代码就是这样很简单。类里面神声明一个变量i,创建两个线程,Task任务类的工作是判断如果i==0的话,就讲i=123,但是我主方法变量i的时候,i的值还是0,并没有被线程修改啊。不是说volatile修饰的变量是都是可见的嘛?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
int 不是引用传递的,线程修改的应该已经不是那个volatile 的 i 了。
===================================
先把这个输出搞清再说:https://onlinegdb.com/rJ0braKMH
输出:
虽然没有看到你的
Task
是咋写的,但是像这样只把一个 int 传进去,如果 Task 里只操作这个 int 的话,是没有办法改变你的 TaskVol.i 的。兄弟,首先你的这个事例并不能很好的验证
volatile
的内存可见性。因为计算机的速度实在是太快了,你仅用两个线程几乎不可能看到被volatile
修饰的变量和不被volatile
修饰的变量有什么不一样的表现。关于
volatile
关键字的语义我想你应该记住和理解一下两点就够了:volatile
修饰的变量对所有其他的线程的可见性volatile
修饰的变量禁止指令重排优化。以下是根据你的代码稍作修改验证
volatile
:以上代码你可以试着分别执行被volatile关键字修饰和不被volatile修饰。会看到不被volatile修饰的话,线程
t1
的死循环根本停不下来,这就说明了t2
线程对变量i的修改,线程t1
是不可见的。但是如果变量i
被volatile修饰的话,t1中的死循环会立马停下来。Java中函数参数都是按值传递, new Task(TestVol.i)会将TestVol.i的值复制一份, 交给Task对象. 实际上Task对象指向的i已经不是TestVol.i了.
这里例子能否满足需求,因为这里有四步,不能保证可见性的,只能简单的推理一下
只有
num = index;
这一步有可见性加上 before 和 normal 、sleep 总共四步,部分 before 可以看到有改变的
3 - before - Thread-44
部分log