JAVA内存模型—JMM

在今天和明天之间,有一段很长的时间;趁你还有精神的时候,学习迅速地办事。 —— 歌德
在介绍java内存模型之前,先提出一个问题,如何保证一个线程看到的数据是正确的?大家可能认为这个问题很没有意思,很简单,在一个线程里,程序都是串行化执行的,你读取到的数据肯定是正确的。现在,我们讨论的是多线程,在多线程里,数据的一致性就变得比较复杂了。
JAVA虚拟机规范定义了一种JAVA内存模型,来实现Java程序在各种平台都能达到一致的内存访问效果。在JDK1.5发布之后,Java内存模型已经变得成熟和完善起来了。JMM主要围绕多线程的原子性、可见性、有序性来建立。
我们首先了解一下这些概念。
原子性:一个操作是不可以中断的。表示即使是在多线程中,一个操作一旦开始,就不会被其它线程所干扰。大部分基本数据类型都具有原子性,但是有两个是例外的,long、double(64位),在32位的操作系统中,它们分为两次读写,如果多个线程对它们进行读写操作,可能会导致读取结果天差地别,我们可以使用volatile保证原子性。另外,sychronized也能保证原子性。
可见性:可见性是指当一个线程修改了共享变量时,其它线程能够立即发现这个修改。可见性主要体现在多线程程序中,单线程是不存在可见性问题的。在java内存模型中,一个线程修改共享变量后,会把修改后的值同步到主内存中,其它线程在读取值时,先从主内存刷新值到工作内存,实现可见性。在多线程中,普通变量不能保证可见性,因为变量的修改可能没有立即同步到主内存中,我们可以使用volatile、synchronized实现这一点。
有序性:有序性可以理解为代码的执行是从先往后,依次执行的。在单线程中,所有的代码都是串行化执行,是有序的。在多线程中,并不能体现有序性,Java虚拟机在对代码进行优化的时候,可能进行指令重排,导致执行顺序不一致。指令重排,是无法预测的,我们只需要记住,Java虚拟机指令重排进行优化,只能保证串行语义一致,并不能保证多线程间的语义也一致。volatile、sychronized可以实现代码的有序性。
当我们了解到这三个基本概念之后,大家有没有觉得sychronized好像是万能的。当然,大部分的并发控制都可以使用sychronized来实现,但是,正是因为它的万能,导致程序员对它非常依赖,在编程的时候没有思考,应当如何高效的实现并发控制,这是后话,略过。另外,我们还需要注意一点,volatile只能保证可见性和有序性,并不能保证原子性,要想完全的保证原子性,我们还是需要使用sychronized或java.util.concurrent中的原子类。
如果程序中,所有的代码我们都使用volatile、sychronized来实现有序性,那么,一些操作可能变得很烦琐。大家平常可能并没有使用这两个关键字,但是也能保证大部分代码的有序性,这是因为JAVA内存模型中定义了一个先行发生(happens-before)原则,下面我们来具体说一下有哪些happens-before原则:
>程序次序规则:一个线程内保证语义的串行性,书写在前面的操作先行发生于书写在后面的操作。
>volatile规则:volatile变量的写操作先行发生于读操作,保证了volatile变量的可见性。
>锁规则:一个unlock操作先行发生于后面对同一个锁的lock操作。注意,是针对的同一个锁。
>传递性:如果操作A先行发生于操作B,操作B先行发生于操作C,那么操作A一定先于操作C执行。
>线程启动规则:线程的start()方法先于此线程的每一个动作。
>线程终止规则:线程中的所有操作都先行发生于线程的终止。
>线程中断规则:线程的中断先于被中断线程的代码。这里可以理解为,对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测是否线程中断。
>对象终结规则:一个对象的初始化完成先行发生于它的finalize()方法的开始。finalize()方法在对象销毁前执行。
Java代码无需使用任何同步操作就能使用上面的规则。
在这里,围绕原子性、可见性、有序性,简单的介绍了Java内存模型,如果大家认为有不对的或者需要改进的地方,望帮忙指正,大家共同学习,一起进步。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值