设为首页 加入收藏

TOP

Java 虚拟机 12 :Java 内存模型(二)
2018-04-03 09:08:32 】 浏览:348
Tags:Java 虚拟 内存 模型
的字段在构造器中一旦初始化完成,并且构造器没有把this传递出去,那在其他线程中就能看见final字段的值。

3、有序性(Ordering)

Java程序中天然的有序性可以总结为一句话:如果在本线程内观察,所有的操作都是有序的;如果在一个线程中观察另外一个线程,所有的操作都是无须的。前半句是指”线程内表现为穿行的语义”,后半句是指”指令重排序”和”工作内存与主内存同步延迟”现象。Java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性,volatile关键字本身就包含了禁止指令重排序的语义,而synchronized则是由”一个变量在同一时刻只允许一条线程对其进行lock操作”这条规则获得的,这条规则规定了持有同一个锁的两个同步块只能串行地进入

先行发生happens-before原则

如果Java内存模型中所有的有序性都仅仅靠volatile和synchronized来完成,那么有一些操作将变得很繁琐,但是我们在编写Java代码时并未感觉到这一点,这是因为Java语言中有一个”先行发生(happens-before)”原则。这个原则非常重要,它是判断数据是否存在竞争、线程是否安全的主要依据,依靠这个原则,我们可以通过几条规则就判断出并发环境下两个操作之间是否可能存在冲突的问题。

所谓先行发生原则是指Java内存模型中定义的两项操作之间的偏序关系,如果说操作A先行发生于操作B,那么操作A产生的影响能够被操作b观察到,”影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等。Java内存模型下有一些天然的,不需要任何同步协助器就已经存在的先行发生关系:

1、程序次序规则:在一个线程内,按照控制流顺序,控制流前面的操作先行发生于控制流后面的操作,说”控制流”是因为还要考虑到分支、循环结构

2、管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作

3、volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作

4、线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作

5、线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测

6、线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生

7、对象终结规则:一个对象的初始化完成先行发生于它的finalize()方法的开始

8、传递新:如果操作A先行发生于操作B,操作B先行发生于操作C,那么操作A必然先行发生于操作C

Java语言无须任何同步手段保障就能成立的先行发生规则就只有上面这些额,如果两个操之间的关系不在此列,并且无法通过下面规则推导出来的话,它们就没有顺序性保障。举一个例子来看一下:

private int i = 0;

public void setI(int i)
{
    this.i = i;
}

public int getI()
{
    return i;
}

很普通的一组getter/setter,假设A线程先调用了setI(1),B线程再调用了同一个对象的getI(),那么B线程的返回值是什么?

依次分析一下先行发生原则中的各项规则。由于两个方法分别由两个线程分别调用,因此程序次序规则这里不适用;由于没有同步块,所以也就没有unlock和lock,因此管程锁定规则这里不适用;i没有被关键字volatile修饰,因此volatile变量规则这里不适用;后面的启动、终止、中断、对象终结也和这里完全没有关系,因此也都不适用。因为没有一个实用的先行发生规则,所以最后一条传递性也无从谈起,因此传递性也不适用。由于所有先行发生原则都不适用,因此尽管线程A的setI(1)操作在时间上先发生,但无法确定线程B的getI()的返回结果,换句话说,这里面的操作不是线程安全的。

那如何修复这个问题?至少有两种比较简单的办法:

1、setter/getter都定义成synchronized的,这样可以套用管程锁定规则

2、i定义为volatile变量,由于setter方法对i的修改不依赖于i的原值,满足volatile关键字的使用场景,这样可以套用volatile变量规则

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇如何定位那些SQL产生了大量的redo.. 下一篇zookeeper 入门系列 – 理论基础..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目