
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
Java编程开发语言是目前大多数人在转行软件开发的时候都会去学习的一种编程开发语言,下面我们就简单来了解一下,Java编程内存模型与规则应用。
一、Java内存模型
Java内存模型(JMM)是一个中间层的模型,是物理内存模型的映射,它为程序员屏蔽了底层的硬件实现细节(CPU缓存一致性及内存屏障等问题),也屏蔽操作系统的内存访问差异,以实现Java程序在各种平台下都能达到一致的内存访问效果。Java内存模型如下图所示:
Java线程对变量的所有操作都在各自的工作内存(主内存的副本)中进行,不能直接读写主内存(volatile变量也不例外),也不能读写其他线程的工作内存。
二、内存可见性
内存可见性是指,一个线程对变量的修改能够立即被其他线程感知到,即能够立即读取到新值。可见性问题的来源是Java内存模型里各线程的工作内存,同时由于指令重排序的存在,使可见性错误总是违背我们的直觉。为确保多个线程之间对内存写入操作的可见性,必须使用同步机制。比如volatile修饰,或者使用锁。
三、Happens-Before规则
编译器生成的指令顺序可以与源代码中的顺序不同。同时,为了提高执行效率,处理器可以采用乱序或并行等方式来执行指令。这些乱序操作的前提是,程序的终结果与在严格串行环境中执行的结果相同。
JMM为程序中的操作提供了一个Happens-Before规则,它是一个原生的规则,无需使用任何同步手段就已经存在,由JVM保证。如果操作A和操作B满足这个规则,那么操作A一定先于B执行,并且A的执行结果对B可见(即B能观察到A产生的影响)。如果两个操作A和B没有Happens-Before关系,那么JVM可以对它们进行任意地重排序,执行结果是无法预测的。这些规则包括:
1.程序顺序规则。在一个线程内,操作A和B按书写的逻辑顺序执行;
2.监视器锁规则。同一个监视器锁上的解锁操作必须在加锁操作之前执行;
3.volatile变量规则。对volatile变量的写入操作必须在对该变量的读取之前执行;
4.线程启动规则。Thread对象的start方法必须在该线程其他任何操作之前执行;
5.线程结束规则。线程中的任何操作都必须在其他线程能检测到该线程已结束之前执行。该线程已结束的标志是从Thread.join()返回,或者Thread.isAlive()返回false;
6.线程中断规则。当一个线程A调用另一个线程B的interrupt()方法时,此方法必须在线程B检测到中断事件之前执行。
7.对象终结规则。对象的构造函数必须在启动该对象的终结器finalize()之前执行完成;
8.传递性。如果操作A在B之前执行,并且操作B在C之前执行,那么操作A必须在C之前执行。
通过Happens-Before规则,可以分析并发环境下两个操作是否可能存在冲突,是否存在安全性问题。Happens-Before规则与时间先后顺序没有因果关系,在分析线程安全问题时不要受时间顺序的干扰。
四、工作内存和主存之间的数据同步
问题:一个线程何时会从主存中去重新读取共享变量的值,又是何时需要将工作内存的值重新刷写到主存中。
前提:不使用volatile关键字保证内存可见性的情况。因为volatile标识的变量告诉JVM此变量是易变的,使线程工作内存的值总是失效而必须每次都从主存取值。
工作内存的值写入主存的时机:线程结束,线程释放锁,线程切换,抛出异常等情况。
线程重新读取主存的值到工作内存的时机:线程切换,获取锁(虽然锁操作只对同步代码块起到作用,但影响的却是线程执行所使用的所有字段),cpu有空闲时间(比如线程sleep,IO操作等)。
【免责声明】:本内容转载于网络,转载目的在于传递信息。文章内容为作者个人意见,本平台对文中陈述、观点保持中立,不对所包含内容的准确性、可靠性与完整性提供形式地保证。请读者仅作参考。更多内容请加danei0707学习了解。欢迎关注“达内在线”参与分销,赚更多好礼。