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

标签: java 并发 编程 | 发表时间:2012-11-20 21:07 | 作者:
出处:http://www.iteye.com

我们先看下面一个示例

  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.
 

已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [java 并发 编程] 推荐:

Java并发编程基础

- - 并发编程网 - ifeve.com
并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力. 如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互性将大大改善. 现代的PC都有多个CPU或一个CPU中有多个核. 是否能合理运用多核的能力将成为一个大规模应用程序的关键. 进程是以独立于其他进程的方式运行的,进程间是互相隔离的.

java 并发编程 synchronized

- - Java - 编程语言 - ITeye博客
同步原语--synchronized. synchronized(class)很特别,它会让另一个线程在任何需要获取class做为monitor的地方等待.class与this做为不同的监视器可以同时使用,不存在一个线程获取了class,另一个线程就不能获取该class的一切实例.. ->线程各自获取monitor,不会有等待..

Java并发编程【1.2时代】

- - 并发编程网 - ifeve.com
         本文介绍了Java原生的多线程技术(1.2),通过详细介绍wait和notify相关的机制、基础的多线程技术以及基于这些技术的等待超时、线程间的通信技术和线程池高阶技术,最后通过一个基于线程池的简单文本web服务器—MollyServer,来阐明多线程带来好处. 通过介绍这些技术,展示了在没有使用Java并发包的时代(1.5-)是如何完成Java的多线程编程,为理解Java5提供了良好帮助.

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

- - ITeye博客
 在ubutun双核cpu下,默认不加任何jvm参数执行. 输出如下: 主线程执行完之后,子线程一直在执行,为什么子线程没有获取到主线程修改done之后的变量值呢. 我们再设置下jvm的参数为 -client,则子线程能够获取主线程修改done之后的值,正常执行完. 也就是moren ubutun下默认jvm启动是-server 服务器默认启动的,那么-server启动跟client启动有什么区别呢.

java并发编程实践学习笔记

- - zzm
    原子操作:原子为不可再分操作.    Violation :可见关键字.    Synchronized:内部隐示锁 .    ReentrantLock:显示锁 .    ReentrantReadWriteLock:读写锁 . jmm(java内存模型):. 线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递 均需要通过主存完成.

Java并发编程-生成唯一序列号

- - 编程语言 - ITeye博客
package com.league.idgenerate; /** * * ID生成器接口, 用于生成全局唯一的ID流水号 * * @author Ivan.Ma */ public interface IdGenerator {. * 生成下一个不重复的流水号. package com.league.idgenerate; /** * ID生成器的配置接口 * @author Ivan.Ma */ public interface IdGeneratorConfig {.

关于Java并发编程的总结和思考

- - ImportNew
并发其实是一种解耦合的策略,它帮助我们把做什么(目标)和什么时候做(时机)分开. 这样做可以明显改进应用程序的吞吐量(获得更多的CPU调度时间)和结构(程序有多个部分在协同工作). 做过Java Web开发的人都知道,Java Web中的Servlet程序在Servlet容器的支持下采用单实例多线程的工作模式,Servlet容器为你处理了并发问题.

Java编程规范

- - Web前端 - ITeye博客
本文档的编写从简,绝大多数内容以条款或者表格形式列出,不做过多的补充说明,代码格式规范遵循eclipse的默认编码规范要求. •    简单,易执行. 1.    名字含义要明确,做到见名知义,如: User,Role, UserManager. 2.    尽量使用英文名字作为变量名,如果要使用中文,请写上备注.

java编程风格指南

- - 行业应用 - ITeye博客
受不了的可以直接到以下网址查看. 作者:Hawstein 出处:http://hawstein.com/posts/google-java-style.html 声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处.

面向GC的Java编程

- - 并发编程网 - ifeve.com
Java程序员在编码过程中通常不需要考虑内存问题,JVM经过高度优化的GC机制大部分情况下都能够很好地处理堆(Heap)的清理问题. 以至于许多Java程序员认为,我只需要关心何时创建对象,而回收对象,就交给GC来做吧. 甚至有人说,如果在编程过程中频繁考虑内存问题,是一种退化,这些事情应该交给编译器,交给虚拟机来解决.