这段代码为什么会输出a:1,b:3呢, 我加了volatile关键字,不是一个线程修改了值,对另一个线程可见吗 ?
public class Test4 {
//加了volatile,为什么会出现: a:1,b:3
volatile long a = 1;
volatile long b = 2;
public void change(){
a = 3;
b = a;
}
public void print(){
System.out.println("a:"+a+",b:"+b);
}
public static void main(String[] args) {
while (true){
final Test4 test4 = new Test4();
new Thread(new Runnable() {
@Override
public void run() {
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
test4.change();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
test4.print();
}
}).start();
}
}
}
volatile 只能保证单个变量的修改是原子的
a = 3;
b = a;
这样分两行写,还是需要同步的。
volatile能够保证对变量的操作是原子的,但是 a = 3, b = a;两个赋值操作不是原子的,在给a赋值3的时候,b 可能已经拿到了a 之前的值
a = 3;
b = a;
给这两个加上同步也会有a:1,b:3,,或者a:1,b:2,,加上同步锁,,不影响第二个线程,,第二个线程不访问change()方法
问题在这里,,连个线程,,一个改连个数,,一个读取两个数(太乱了,)
有a:1,b:3,,或者a:3,b:2,,等是必然现象啊
原因如下:
【1】线程运行时随时可能发生调度,
【2】当第一个线程刚刚修改完两个数时,,第二个线程进去读,,读到的结果就是 a:3 b:3
【3】当第一个线程刚刚初始化修改完a时还未修改,发生调度,,,第二个线程进去读,,读到的结果就是 a:3 b:2(几率比较小,还是有的。)
.....剩下情况同理
最后分析一下为什么会出现【a:1,b:3】
System.out.println("a:"+a+",b:"+b);。内部是实现其实也是一个字符一个字符写到buffer中,然后刷到控制台
初始化玩a,b【a=1,b=2】,第二个线程开始输出方法 当写完【"a:"+a】时,,调度了,,还有【",b:"+b】没来得及写
第一个线程运行,修改完a和b,,【a=3,b=3】,,修改完,第二个线程开始运行了,,继续刚才的输出,,写【",b:"+b】,,此时b等于3
结果就会出现【a:1,b:3】这种情况。
有问题还可以追问,,以上仅是个人观点,,如有错误请指出【嘿嘿,共同探讨】。