关键字volatile,公共堆栈,私有堆栈,非原子特性

一、公共堆栈与线程的私有堆栈

在启动线程时,变量的值是存在于公共堆栈及线程的私有堆栈中。在JVM被设置为-server 模式时为了线程运行的效率,线程一直在私有堆栈中取变量的值,即使有其他线程将变量的值进行了修改,更新的却是公共堆栈中的变量值,私有堆栈中的值不会变,这就导致线程运行存在问题。内存关系如图:

····························内存关系如图

volatile作用

使用volatile 关键字,可以强制的从公共内存中读取值。使用volatile关键字增加了实例变量在多个线程之间的可见性。但是volatile关键字的缺点是不支持原子性。

volatile与synchronized 比较

1)volatile 是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,但是volatile只能修饰变量,而synchronized可以修饰方法,代码块。
2)多线程访问volatile 不会发生阻塞,而synchronized 会发生阻塞。
3)volatile 能保证数据的可见性,但不能保证原子性,而 synchronized可以保证原子性,也可以保证可见性,因为它会将私有内存和公共内存中的数据做同步。

volatile的非原子特性
  1. 程序的原子性概念:一个操作的过程是不可中断的,要么全部执行成功要么全部执行失败,有着“同生共死”的感觉。即使在多个线程一起执行的时候,一旦一个原子性的操作开始后,就不会受其他线程的干扰。

  2. 验证

public class MyThread extends Thread{
	// static修饰的变量只被初始化一次,下一次依据上一次结果值
	volatile public static int count;
	private static void addCount(){
		for (int i = 0; i < 100; i++){
			count++;
		}
		System.out.println("count="+count);
	}
	@Override
	public void run(){
		addCount();
	}
}
public class VolatileRun {

	public static void main(String[] args) {
		MyThread[] mythreadArr = new MyThread[100];
		// 创建 100个实例
		for(int i = 0; i < 100; i++){
			mythreadArr[i] = new MyThread();
		}
		for(int i = 0; i < 100; i++){
			mythreadArr[i].start();
		}
	}
}

运行结果:不是10000
··························运行结果

        关键字volatile 提示线程每次从公共堆栈读取值,而不是从私有内存中读取,这样就保证了数据的同步数据可见性。但是:如果修改实例变量中的数据,比如 i++,也就是i = i+1,则这样的操作其实并不是一个原子操作,也就是非线程安全的。表达式i++ 的操作步骤分解如下:
        1)从内存中取出 i 的值;
        2)计算 i 的值;
        3)将 i 的值写到内存中

        假如在第2步计算值的时候,另一个线程也修改了 i 的值,那么这时候就会出现脏数据。解决办法就是使用synchronized 关键字。所以说 volatile 本身并不处理数据的原子性,只是强制数据的读写及时影响到主内存中。

  1. 用图来演示下volatile出现非线程安全的原因。变量在内存中工作的过程。
            1)read 和 load 阶段:读取和加载
            2)use 和 assign 阶段: 操作和赋值
            3)store 和 write 阶段:储存和 写
    变量在内存中的工作过程
            在多线程环境,use和assign 是多次出现的,但这一操作不是原子性的,在read和load之后,如果主内存的count变量的值修改之后,线程工作内存中的值 由于已经加载,不会产生对应变化,也就是私有内存和公共内存中的变量不同步了,所以计算出的结果和预期结果不一样,也就出现了非线程安全的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值