JAVA并发编程--volatile关键字

volatile关键字:

  1. 保证线程间的可见性
  2. 禁止指令的重排序
  3. 不能保证原子性,所以不是线程安全的

线程间可见性

import java.util.concurrent.TimeUnit;

public class test extends Thread {
	volatile int x = 0;//此处可以将volatile去除 或者 替换为 static,经过对比可看出volatile的作用

	private void write() {
		x = 5;
	}

	private void read() {
		while (x != 5) {
		}
		if(x == 5){
			System.out.println("------stoped");
		}
	}

	public static void main(String[] args) throws Exception {
		test example = new test();


		Thread writeThread = new Thread(new Runnable() {
			public void run() {
				example.write();
			}
		});


		Thread readThread = new Thread(new Runnable() {
			public void run() {
				example.read();
			}
		});

		readThread.start();


		TimeUnit.SECONDS.sleep(5);//记住此处一定要暂停5秒,以保证writeThread一定会在readThread中执行
		System.out.println("------");
		writeThread.start(); 
	}
}

如果不加volatile关键字,readThread 在while循环中高频率的读取x的值,此时读取是readThread 的工作内存中的值,一直是0。虽然writeThread将x赋值为5,但readThread 一直读取的不是最新值,导致程序一直运行不退出。
加了volatile关键字,writeThread修改的值会立刻写入主存,readThread 读取的也是主内存最新的值,所以会打印"------stoped",并结束程序。

禁止指令重排序
为什么会有指令重排序:

  1. 在虚拟机层面,为了尽可能减少内存操作速度远慢于CPU运行速度所带来的CPU空置的影响,虚拟机会按照自己的一些规则(这规则后面再叙述)将程序编写顺序打乱——即写在后面的代码在时间顺序上可能会先执行,而写在前面的代码会后执行——以尽可能充分地利用CPU。
  2. 在硬件层面,CPU会将接收到的一批指令按照其规则重排序,同样是基于CPU速度比缓存速度快的原因,和上一点的目的类似,只是硬件处理的话,每次只能在接收到的有限指令范围内重排序,而虚拟机可以在更大层面、更多指令范围内重排序

使用volatile关键字会禁止指令的重排序

不能保证原子性,所以不是线程安全的

public class test {
	public volatile int inc = 0;

	public void increase() {
		inc++;
	}

	public static void main(String[] args) {
		final test test = new test();
		for(int i=0;i<10;i++){
			new Thread(){
				public void run() {
					for(int j=0;j<1000;j++)
						test.increase();
				};
			}.start();
		}

		while(Thread.activeCount()>1) //保证前面的线程都执行完
			Thread.yield();
		System.out.println(test.inc);
	}
}

加volatile关键字和不加发现最后输出的inc的值都不一定是10000;所以volatile不是线程安全的。
保证线程安全使用synchronized, lock。加上锁之后可保证每次输出的结果都是10000,不放代码了,可自行在increase方法上尝试。

注:可能有人不理解,volatile在并发编程中并不常用,但为什么还要学习它呢?
我来说明一下,因为它对理解Java内存模型很有用,用懂了这个关键字是对JMM很好的理解过程。
实际上对于线程间的可见性,不加此关键字的变量在线程A中操作后,早晚也是要同步到主线程的,volatile只是加快了这个时间。在现代版本的JVM中,优化了运行效率,所以立即同步特点不会特别明显,不过为了更好的学习和理解Java运行过程,我们仍然需要清楚这个关键字的含义呀。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值