java多线程之volatile关键字与线程栈内存

不使用volatile,开100个进程自增:

package com.wanggang.java.test;

public class ThreadTest3 {
	public static int countInt;
	public volatile static int countIntVolatile;//volatile告诉编译器该值是随时发生变化的,不进行编译优化
	public static void main(String[] args) {
		for(int i=0;i<10;i++){
			new Thread(new Runnable() {//new 100个线程处理自增
				public void run() {//重写runnable里面的run()方法
					countThread();
					System.out.println(countInt);
					//System.out.println(countIntVolatile);
				}
			}).start();
		}
		System.out.println("The Result of countInt is "+countInt);
		//System.out.println("The Result of countIntVolatile is"+countIntVolatile);
	}

	public static void countThread(){
		try {
			Thread.sleep(10);//让线程睡10ms让结果明显
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		countInt++;
		countIntVolatile++;
	}
}


结果是:

The Result of countInt is 0
2
3
2
2
4
9
8
7
6
5

可以看出在有三个进程读到了countInt=1时,写countInt=2写了三次,最后也没有加到10。


加上volatile关键字后:(去掉上代码注释)

结果为:

The Result of countIntVolatile is 0
2
2
3
4
5
6
10
9
8
8

从两个2,两个8也能得出volatile并没有实现一个线程对countIntVolatile 的 (读写)是一个原子操作。


为什么?

jvm主内存与线程内存交互:


一个线程对一个变量进行操作时,先对通过找到这个变量的引用来read它在堆内存中对应的值,然后load到线程本地内存,之后的use和asign(赋值)都在线程本地内存中进行。最后store到线程本地内存,write到主内存,实现线程内存与主内存之间的同步。需要注意到,这一个完整的(读写)并不是一个原子操作。

所以,当线程A读到countInt=1时,还没对主内存进行write时,线程B已经read,load到countInt=1,所以当线程B也write到主内存时会出现多个输出为2。

而volatile关键字只能保证在主内存中读取的是变量的最新值,所以加了volatile后也一样的。

所以volatile不是线程安全的,同步锁不能省。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值