并发编程——为什么volatile变量++操作线程不安全

学习volatile的时候也许我们会看到下面这句话:

对于volatile变量来说,自增操作线程不安全。

 

那为什么不安全呢?本帅博主看的是《并发编程的艺术》这本书,这本书对这一事件也没有做出很让人易懂的解释。那么我们自己用例子来测试一下咯~

测试代码如下: 

package xiancheng;

public class volatileTest {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		VolatileExample example=new VolatileExample();
		Thread thread1=new Thread() {
			public void run(){
				for(int i=0;i<100000;i++) {
					example.getAndIncrement();
				}
			}
		};
		Thread thread2=new Thread() {
			public void run(){
				for(int i=0;i<100000;i++) {
					example.getAndIncrement();
				}
			}
		};
		thread1.start();
		thread2.start();
		Thread.sleep(6000);//等一会,让线程都执行完。
		System.out.println(example.get());
	}

}

class VolatileExample{
	volatile int v=0;
	public  void set(int  l) {
		v=l;
	}
	public void getAndIncrement() {
        v++;
	}
	public  int get() {
		return v;
	}
}

在上面这个代码中,VolatileExample类汇总声明了一个volatile变量v,以及三个方法,set()、get()和用来进行自增操作的getAndIncrement()方法。

在主函数中,我创建了两个线程,各自循环调用VolatileExample类的实例volatileExample中的getAndIncrement()方法100000次。

如果volatile保证++安全,那么执行结果将是200000.

那么真实结果是多少呢?

多执行几次:

    

从上面几次的执行结果我们可以看到,始终都不到200000万。这样的结果表明volatile不保证volatile++这样的操作具有原子性。

为什么呢?

其实很简单,因为“++”属于复合操作。

上面的VolatileExample其实等价于一下的代码:

class VolatileExample{
	int v=0;
	public synchronized void set(int  l) {
		v=l;
	}
	public void getAndIncrement() {
		int temp=get();
		temp+=1;
		set(temp);
	}
	public synchronized int get() {
		return v;
	}
	
	
}

如果不清晰的话,我们可以通过javap反编译一下。 

使用javap对VolatileExample类进行反编译,出来的结果如下: 

我们可以看到,getAndIncrement()方法中的v++语句被编译成了 七条语句,这属于复合操作。

v++其实相当于:

  1. 读v
  2. 对v+1;
  3. 将原来的v值置为v+1。

 volatile保证可见性,当进行++操作的时候,volatile保证第一条指令正确,即读正确。当执行接下来的指令的时候,其他线程可能对v加大了,当将v存回去的时候(即执行putfield指令的时候),可能将一个更小的v同步回主内存去了。所以最终得到的数字就会小于200000.

总结:volatile的读写具有原子性,但是自增操作属于复合操作,因此不具有原子性,所以线程也不安全。

 

好啦,以上就是关于volatile变量自增是否线程安全的相关知识总结,如果大家有什么不明白的地方或者发现文中有描述不好的地方,欢迎大家留言评论,我们一起学习呀。

 

Biu~~~~~~~~~~~~~~~~~~~~宫å´éªé¾ç«è¡¨æå|é¾ç«gifå¾è¡¨æåä¸è½½å¾ç~~~~~~~~~~~~~~~~~~~~~~pia!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值