`
臻是二哥
  • 浏览: 183403 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
Group-logo
Java技术分享
浏览量:0
社区版块
存档分类
最新评论

JAVA并发-DCL与JMM

阅读更多
首先必须声明,在volatile出现之前,错误的DCL代码如下。在volatile出现之后,正确的DCL代码如下。代码如下:
//错误的代码
public class Singleton {
	private static Singleton instance=null;
	private Singleton(){}
	public static Singleton getInstance(){
		if(instance==null){
			synchronized (Singleton.class) {
				if(instance==null)
					instance=new Singleton();//mark行			
			}			
		}
		return instance;
	}
}

//正确的代码
public class Singleton {
	private volatile static Singleton instance=null;//添加了volatile修饰符
	private Singleton(){}
	public static Singleton getInstance(){
		if(instance==null){
			synchronized (Singleton.class) {
				if(instance==null)
					instance=new Singleton();				
			}			
		}
		return instance;
	}
}


我们来剖析错误的代码:
在错误的DCL代码中,代码行mark在JVM中有2种可能的执行顺序(JVM会对一些没有依赖要求的指令重排序。关于重排序,在下文中进行说明),分别为:
//第一种执行顺序
mem=allocate()
mem.initial()
instance=mem

//第二种执行顺序
mem=allocate()
instance=mem
mem.initial()

假设现在有2个线程a和b,线程a执行到mark行语句并按照第二种执行顺序执行完instance=mem指令。此时线程b执行getInstane方法会直接返回一个非空的instance,但是这个instance可能是未被完整创建的。这个时候,DCL就出问题了。这就是大家对DCL口诛笔伐的原因。由此可见,错误的DCL的真正问题就在于:在没有同步的情况下读取一个共享变量,可能读到不完整的实例。也就是说,不在同步代码块中的if(instance==null)代码可能读取到不完整的instance实例。

为了解决类似DCL中出现的问题,JAVA在JMM中(JAVA内存模型)定义了一系列Happens-Before关系。如果两个操作之间缺少Happens-Before关系,那么JVM就可以对它们任意的重排序。比如volatile变量规则规定:对volatile变量的写入操作必须在对该变量的读操作之前进行。这就是DCL在使用volatile之后变得正确的原因。

重排序:
下面的代码可能的输出结果有:<1,1><1,0><0,1><0,0>这四种,首先,两个线程的先后执行顺序不同,可能one先(结果是<0,1>),可能two先(结果是<1,0>),可能one和two交替执行(结果是<1,1>);其次,由于每个线程内部的各个操作之间不存在依赖性,因此这些操作可以重排序(结果可能为<0,0>)。可见,内存级别的重排序会令程序变得不可预测,因此需要正确的使用同步,以使程序满足JMM要求的可见性规则。
public class Demo{
	static int x=0,y=0;
	static int a=0,b=0;
	public static void main(String [] args) throws InterruptedException {
		Thread one=new Thread(new Runnable() {
			@Override
			public void run() {
				a=1;
				x=b;				
			}
		});
		Thread two=new Thread(new Runnable() {
			@Override
			public void run() {
				b=1;
				y=a;
			}
		});
		one.start();    two.start();
		one.join();		two.join();
		System.out.println("<"+x+","+y+">");
	}
}

0
2
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics