
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
内存模型的应用与管理是大多数Java程序员都需要熟练掌握的一个编程知识点,而本文我们就通过案例分析来简单了解一下,Java编程内存管理分享。
1、线程之间如何通信以及线程之间如何同步?
通信是指线程之间以何种机制来交换消息,在命令式编程中,线程之间通信方式有两种:共享内存和消息传递。
同步是指程序中用于控制线程间操作发生相对顺序的机制。
在共享内存模型中,通信是隐式的,同步时显式的。共享内存模型是指线程间通过写-读内存中的公共状态来通信或同步。
在消息传递模型中,通信是显示的,同步是隐式的。消息传递模型是指线程间通过发送消息来通信或同步。
Java的并发采用的是共享内存模型。
2、Java内存模型
同CPU内存模型一样,Java也有自己的内存模型。
Ⅰ、CPU内存模型
Ⅱ、Java内存模型
在Java中,所有的实例域、静态域和数组元素都存储在堆内存中,而堆内存在线程之间是可以共享的(共享变量)。
局部变量、方法定义参数和异常处理器参数存储在栈中,不会再线程之间共享,它们不会存在内存可见性的问题。
Java线程之间的通信由Java内存模型(简称JMM)控制,JMM决定一个线程堆共享变量的写入何时对另一个线程可见。
3、volatile重排序
在执行程序时,为了提供性能,编译器和处理器常常会对指令做重排序。
通常为了遵循as-if-serial语义,编译器和处理器都不会对存在数据依赖关系(控制依赖除外)的操作做重排序。
as-if-serial语义是指:不管怎么重排序,(单线程)程序的执行结果不能被改变。
重排序分三种类型。
Ⅰ、编译器优化重排序:编译器在不改变单线程程序语义的情况下,可以重新安排语句的执行顺序。
Ⅱ、指令级并行重排序:如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
Ⅲ、内存系统重排序:因为处理器使用缓存读写缓冲区,所以加载和存储有可能乱序执行。
为了保证内存可见性,Java编译器在生成指令序列的适当位置会插入内存屏障指令来禁止特定类型的处理器重排序(非编译器)。
4、未同步程序的执行特性
对于未同步或未正确同步的多线程程序,JMM只提供小安全性:
线程执行时读取到的值要么是之前某个线程写入的值,要么是默认值(0,Null,False)。
为了实现小安全性,JVM在堆上分配对象时,先会对内存空间进行清零,然后才会在上面分配对象(JVM内部会同步这两个操作)。
另外,JMM不保证对64位的long型和double型变量的写操作具有原子性。
因为在32位的机器上保证对64位数据的写操作具有原子性,会有比较大的开销。
为了照顾这种处理器,Java语言鼓励但是不强求JVM对64位的long型变量和double型变量的写操作具有原子性。
当JVM在这种机器上运行时,可能会把对64位long/double的写操作拆为两个32位的写操作来执行。
在JSR-133之前旧的内存模型中,一个64位long/double型变量的读/写操作可以拆分为两个32位的读/写操作来执行。
从JSR-133内存模型开始(JDK5开始),仅仅允许把一个64位long/double型变量的写操作拆分为两个32位的写操作来执行。
5、volatile写-读的内存语义
当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量的值刷新到主内存。
当读一个volatile变量时,JMM会把该线程对应的本地内存(缓存)置为无效,线程接下来从主内存中读取共享变量。
【免责声明】:本内容转载于网络,转载目的在于传递信息。文章内容为作者个人意见,本平台对文中陈述、观点保持中立,不对所包含内容的准确性、可靠性与完整性提供形式地保证。请读者仅作参考。更多内容请加danei456学习了解。欢迎关注“达内在线”参与分销,赚更多好礼。