在虚拟机的规范中,定义了Java的内存模型(JMM),来屏蔽各种硬件和操作系统内存访问的差异。在JDK1.5(实现了JSR-133)发布后,Java内存模型就逐渐的完善起来了。
一. 并发编程要解决的关键问题
我们知道,JMM是围绕着并发过程中如何处理原子性,可见性,有序性这3个特征建立的。
1.原子性:有关原子性的内容请参考http://zhaodengfeng1989.iteye.com/blog/2418779
2.可见性:也就是线程之间以何种机制进行信息交互(也叫线程通信)。在命令式编程中,线程之间的通信的方式有两种:共享内存,消息传递。
①共享内存:在共享内存的并发模型中,线程之间共享内存的共享变量,通过线程之间写-读内存中的共享变量,进行线程之间的隐式通信。
②消息传递:在消息传递的并发模型里,线程之间没有公共状态,通过显式发送消息的方式进行显式通信。
3.有序性:也叫线程的同步,是指程序中用于控制线程间操作发生相对顺序的机制。
①在共享内存的并发模型中,需要显式的指定程序中某段代码需要互斥执行,因此线程之间的同步是显式进行的。
②在消息传递的并发模型中,由于消息发送和接收的相对顺序,线程之间的同步是隐式进行的。
Java的并发模型采用的是共享内存的方式,Java线程之间通过共享内存进行隐式通信,对外部完全透明,也就是我们今天看到Java内存模型。
二.Java内存模型的结构(也叫抽象结构)
1.线程之间如何通信
在虚拟机的体系结构中,我们知道堆内存和方法区是所有线程共享的。因此我们所说的共享内存模型,也建立在这两块区域上。因此,共享变量就是在共享内存中定义的变量,包括对象实例,静态域,数组元素。
我们来看一下JMM的抽象结构图:
从抽象出来的JMM结构看,JMM定义了线程与主内存(共享内存)之间的关系,每个线程都有一个私有的本地内存(Local Memory),在本地内存中存放着共享变量的副本。当然,线程的本地内存是JMM中抽象出来的一个概念,它涵盖了处理器的缓存,读写缓冲区,寄存器,一部分硬件以及编译器优化。
根据JMM的抽象结构,我们说下在共享内存的并发模型下,线程之间是如何通信的。
根据上图,我们可以知道,线程A,B之间要通信,必须要进行两步。
一是线程A把本地内存中更新过的共享变量副本刷新到主内存中;
二是线程B从主内存中读取线程A更新过的共享变量。
我们举一例详细说明。假设现在有两个线程,线程A,B,并且线程A,B的本地内存中都缓存了共享变量x,且x是初始状态值为0.
当线程A更新了共享变量x=1后,根据JMM的抽象结构,我们知道线程A,B之间要通信,那么需要做的第一步就是把更新后的x写入到主内存中,那么此时主内存的x=1。然后第二步线程B读取主内存中更新后的变量x=1,缓存在线程B的本地缓存中,那么此时,线程B中的共享变量x也是1(这里面涉及的机制参见帖子http://zhaodengfeng1989.iteye.com/blog/2418346)。过程见下图。
从以上可以看出,JMM通过控制主内存(共享内存)和线程本地内存的交互来进行线程之间的通信。
2.线程执行如何进行有序性操作?
从Java源代码到最后在处理器上实际执行的指令序列,会经历3种重排序。
①编译器优化重排序:在不改变单线程串行语义的前提下,可以重新安排语句的执行顺序。
②指令级并行重排序:现代处理器采用了指令级并行技术(ILP,Instruction-Level-Parallelism)来将多条指令重叠执行,如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序,从而形成指令流水线。
③内存系统的重排序:由于处理器使用缓存和写缓冲区,使得加载(读)和存储(写)操作看上去乱序执行。
上述①属于编译器重排序,②③属于处理器重排序。
我们一定要记住的是,
对于编译器,JMM的编译器重排序规则会禁止特定类型的编译器重排序。
对于处理器重排序,JMM的处理器重排序规则会要求在Java编译器生成指令序列时,插入特定类型的内存屏障指令(Memory Barrier/Fence),通过特定的内存屏障指令来禁止特定类型的处理器重排序。
下一帖我们重点说下重排序和先行发生(Happen-before)原则相关内容,他们是理解JMM的关键!!
相关推荐
- **JMM**:Java内存模型定义了线程如何访问和更新共享变量,以及如何确保多线程环境下的可见性和一致性。JMM通过内存屏障和volatile、synchronized关键字来保证并发编程的安全性。 5. **并发的优势与风险** - **...
Java 多线程是Java语言中的一个重要特性,...总的来说,Java多线程编程涉及许多概念和机制,包括线程创建、同步、通信、异常处理等。理解和熟练掌握这些知识点是开发高并发应用的基础,也是提升Java程序员技能的关键。
通过阅读《Java-jdk10-最新最全多线程编程实战指南-核心篇》这本书,开发者不仅可以理解Java多线程编程的基础知识,还能掌握高级并发编程技巧,从而在实际项目中实现高性能、高并发的程序设计。对于Java开发者来说,...
Java多线程是并发编程的重要组成部分,理解和掌握其基础以及Java内存模型对于任何Java开发者来说都是必不可少的。本文将深入探讨这两个主题。 首先,我们来理解多线程的生命周期及其五种基本状态: 1. 新建状态...
- **并发模型**:Java采用基于共享内存的并发模型,线程间通过共享变量进行通信,同时提供了同步机制防止数据竞争。 2. **同步控制** - **同步原语**:包括`synchronized`关键字、`volatile`关键字、`Lock`接口...
在并发领域,"并发面试专题.pdf"可能会包含线程安全、锁机制、并发工具类如Semaphore、CountDownLatch和CyclicBarrier,以及Java内存模型(JMM)等内容。求职者需要了解如何避免死锁,掌握线程池的工作原理,以及...
8. **多线程**:Java内置了对多线程的支持,通过Thread类或实现Runnable接口可以创建和管理线程,理解同步机制(如synchronized关键字、wait()、notify()、notifyAll())和并发工具类(如Semaphore、CyclicBarrier)...
【Java基础】 Java语言是面向对象的...总结:本篇笔记涵盖了Java基础、集合框架、并发编程和设计模式等多个方面,是准备Java后端开发面试的重要参考资料。深入理解这些知识点,有助于在面试中展现出扎实的技术功底。
理解Java内存模型(JMM)和垃圾收集机制对于优化程序性能至关重要。你将学习到堆内存的划分、对象的生命周期、引用类型,以及各种垃圾收集算法如标记-清除、复制、标记-整理和分代收集。 **6. 异常处理** 异常处理...
理解并发模型和JVM内存模型(JMM)有助于解决多线程问题。 Java反射机制允许程序在运行时检查和修改自身的行为,面试中可能会考察Class类、Constructor、Method和Field的使用。垃圾收集(GC)和内存管理也是面试的...
2. 内存模型:Java内存模型(JMM)如何确保多线程环境下的数据一致性,理解主内存、工作内存、 volatile、synchronized、final关键字的作用。 3. 内存分区:Java堆、栈、方法区、本地方法栈的划分,重点理解新生代...
- **Java内存模型JMM**:定义了主内存与线程工作内存之间的抽象行为。 **1.6 设计模式** - **常见的设计模式**:单例模式、工厂模式、策略模式、观察者模式等。 - **设计模式的六大原则**:单一职责原则、开放...
本书《Java宝典》旨在帮助读者深入理解Java的核心技术,包括JVM、类加载机制、多线程处理、网络编程、非阻塞I/O(NIO)、性能优化以及安全等方面。这些都是在Java面试中经常被提及的知识点。本书通过精选国内外优秀的...
候选人需要熟悉Java内存模型(JMM),理解synchronized、volatile、ThreadLocal等关键字的作用,同时掌握ReentrantLock、CountDownLatch、CyclicBarrier、Semaphore等并发工具类的使用。 "Idea使用笔记"则是关于...
2. **多线程与高并发**:探讨在单机环境下如何通过多线程实现高并发处理。 3. **JVM调优**:学习JVM的基础知识,包括Class加载、内存模型、GC算法、JVM调优实战等。 4. **JMM(Java内存模型)**:理解Java内存模型的...
对于高级主题,如Java内存模型(JMM)和volatile关键字的作用,也会有深入的讨论。 Java集合框架是另一个重要的学习点,包括ArrayList、LinkedList、HashSet、HashMap等数据结构的使用场景、性能特点以及它们的底层...