java并发编程下变量可见行分析

我们先看下面一个示例

  public class RaceCondition {
	private static boolean done;

	public static void main(final String[] args) throws InterruptedException {
		new Thread(new Runnable() {
			public void run() {
				int i = 0;
				while (!done) {
					i++;
				}
				System.out.println("Done!");
			}
		}).start();
		System.out.println("OS: " + System.getProperty("os.name"));
		Thread.sleep(2000);
		done = true;
		System.out.println("flag done set to true");
	}
}

在ubutun双核cpu下,默认不加任何jvm参数执行

输出如下: 主线程执行完之后,子线程一直在执行,为什么子线程没有获取到主线程修改done之后的变量值呢?

 

我们再设置下jvm的参数为 -client,则子线程能够获取主线程修改done之后的值,正常执行完


也就是moren ubutun下默认jvm启动是-server 服务器默认启动的,那么-server启动跟client启动有什么区别呢?-server启动多了JIT即时编译优化,JIT优化会对while循环进行优化,所以它没法看到主线程对done变量修改的值,子线程读取done变量会从操作系统寄存器或者cpu cache中读取done的值,而不会从主存中读取,而主线程修改done变量还是从放在主存。所以就出现上面这种并发编程的变量可见行问题了。

 

此时 volatile修饰词当然就派上用场了,volatile就是让变量的修改能够让该变量的值从主存中读取,当然更新了各个线程就都能看到了。


 

还有一种方式也可以达到上面的效果,就是使用synchronized同步,synchronized同步也能够让各个线程从主存中获取最新的值。

package com.mime;

public class RaceCondition {
//	private static volatile boolean done;

	public static void main(final String[] args) throws InterruptedException {
		new Thread(new Runnable() {
			public void run() {
				int i = 0;
				while (!getFlag()) {
					i++;
				}
				System.out.println("Done!");
			}
		}).start();
		System.out.println("OS: " + System.getProperty("os.name"));
		Thread.sleep(2000);
		setFlag(true);
		System.out.println("flag done set to true");
	}
	
	private static boolean done;
	public static synchronized boolean getFlag() { return done; }
	public static synchronized void setFlag(boolean flag) { done = flag; }
}

输出同样是:

OS: Linux
flag done set to true
Done!

Simply put, it is the copying from local or working memory to main memory.
A change made by one thread is guaranteed to be visible to another thread only if
the writing thread crosses the memory barriera and then the reading thread crosses
the memory barrier. synchronized and volatile keywords force that the changes are
globally visible on a timely basis; these help cross the memory barrier—accidentally
or intentionally.
The changes are first made locally in the registers and caches and then cross the
memory barrier as they are copied to the main memory. The sequence or ordering
of these crossing is called happens-before—see “The Java Memory Model,” Appendix
2, Web Resources, on page 255, and see Brian Goetz’s Java Concurrency in
Practice [Goe06].
The write has to happens-before the read, meaning the writing thread has to cross
the memory barrier before the reading thread does, for the change to be visible.
Quite a few operations in the concurrency API implicitly cross the memory barrier:
volatile, synchronized, methods on Thread such as start() and interrupt(), methods on Execu-
torService, and some synchronization facilitators like CountDownLatch.


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值