线程学习四:volatile 关键字

很显然,volatile关键字修饰的对象修改后,都能在任何线程中立马拿到

但是你是否注意到了volatile使用上面的2不能1必须呢?

1、不能将volatile使用到频繁更新的值上面

  如下图演示

	public static void main(String args[]) throws InterruptedException {
		for (int i = 0; i < 20; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					for (int i = 0; i < 1000; i++) {
						b++;
					}
				}
			}).start();
		}
		while (Thread.activeCount() > 1) {
			Thread.yield();
		}
		System.out.println(b);
	}
按照道理,我们应该最后输出20000,但是最后输出的结果总是小于20000,且每次不固定 。
究其原因,就是因为 对于某线程A,虽然每次我再进行b++操作之前,都能拿到内存中最新的值,但是我在进行b++之后是要把数据写回到内存中的。 而这时候可能内存中的值已经被其他线程增加了好多次


2、volatile 对象不能与其他非volatile对象联合使用

     例如 c=(volatile b+d);使用C的时候,及时b及时改变了,C值也不会改变


3、jvm指令重排会影响业务的标志性对象 必须使用volatile

    例如

private static boolean b = false;

	private static void changeFlag() {
		//doSomeThingCost 10 seconds //代码1
		b = true; //代码2
	}

	private static void sayHello() {
		while (true) {
			if(b){
				System.out.println("hello");
			}
		}
	}

	public static void main(String args[]) throws InterruptedException {
		new Thread(new Runnable() {
			@Override
			public void run() {
				changeFlag();
			}
		}).start();

		new Thread(new Runnable() {
			@Override
			public void run() {
				sayHello();
			}
		}).start();
	}

如上代码,AB线程基本同时执行,B线程要等A中的代码1执行完后再执行输出hello .  但是由于JVM的指令重排,可能会导致代码2在代码1之前执行,导致提前输出hello。

这样的话,如果是银行等支付付款业务后续处理逻辑,那影响就太大了 。如果加了volatile,那么JVM的指令重排永远不能把代码1放到代码2后面

顺便说一句,内存更新数据是语句级别的,不是方法级别的

验证代码如下,输出为hello= false; 第一个Thread执行了changeFlag(),然后run()并没有执行完,b已经修改为true了。

private volatile static boolean b = false;

	private static void changeFlag() {
		b = true;
	}

	private static void sayHello() {
		System.out.println("hello=" + b);
	}

	public static void main(String args[]) throws InterruptedException {
		new Thread(new Runnable() {
			@Override
			public void run() {
				changeFlag();
				try {
					Thread.sleep(4000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				b = false;
			}
		}).start();
		Thread.sleep(1000);
		new Thread(new Runnable() {
			@Override
			public void run() {
				sayHello();
			}
		}).start();
	}






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值