线程通信和线程同步
并发编程的两个核心问题是线程通信和线程同步,其中线程通信指线程之间以何种机制交换信息。常见的通信机制有两种:共享内存(线程之间共享公共状态,通过读-写公共状态来隐式通信)、消息传递(线程之间通过发送信息来显示通信),java采用共享内存的通行机制。同步指控制不同线程之间操作发生相对顺序(互斥)的机制。本篇主要从java的内存模型角度分析java底层如何保证内存可见性从而确保线程之间能够正常通行。
java 内存模型(JMM)
java线程之间的通讯由JMM控制,JMM决定一个线程对共享变量的写入何时对其他线程可见。
happens-before关系
定义:如果A 操作happends-before B操作,那么A操作的结果将对B操作可见。
判断方法
1、 一个线程中的每个操作 happens-before 于该线程中的任意后续操作。
2、对一个监视器的解锁 happens-before 于随后对该监视器(同一个锁)的加锁。
3、对一个监视器的解锁 happens-before 于随后对该监视器(同一个锁)的加锁。
4、如果A happens-before B 且 B happends-before C ,那么Ahappens-before C。
重排序
重排序分编译器重排序和处理器重排序,编译器重排序是指编译器在不改变单线程程序语义的情况下,可以改变语句的执行顺序,达到优化的目的。处理器重排序是指如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序,达到指令并行执行的目的。
重排序引发多线程的内存可见性问题,JMM会禁止特定类型的编译器重排序,同时在java编译器在生成的指令序列的适当位置插入内存屏障以此来禁止特定类型的处理器从排序。
顺序一致性内存模型对比JMM
顺序一致性模型是一个理想的参考模型,提供了极强的内存可见性保证,JMM参考这个模型。
在顺序一致性模型中,一个线程中的所有操作必须按照程序的流程来执行,不管同步与否,所有线程只能看到一个单一的操作执行顺序,JMM中无此保证,JMM对于同步程序有顺序一致性的效果,未同步程序在JMM中不但整体的执行顺序是无序的,而且所有线程看到的操作顺序也可能不一致,例如:线程A 执行 a=10操作(将值写到本地缓存),在将其刷新到主存之前,此操作只对线程A可见,在其他线程看来,因为看不到a的新值,所以就以为线程A并没有执行此操作。JMM对未同步的程序只提供最小安全性,线程执行时读取的值要么是某个线程写入的值,要么是默认值(0,null,false),不会出现一些无中生有的值。
顺序一致性模型保证对所有的内存读/写都具有原子性。JMM不保证对64位的long 、double变量的读/写操作具有原子性。从jsr-133内存模型开始(jdk5),仅仅只允许把一个64位long/double型变量的写操作拆分成两个32位的写操作来执行,任意的读操作在jsr-133中都具有原子性。
volatile
volatile具有可见性,对一个volatile变量的读,总是能看到对这个volatile变量最后的写入。同时volaile具有原子性,对任意单个volatile变量的读/写具有原子性(对long、double类型很有意义,对v++这种复合操作不具原子性)。
volatile 的写-读与锁的释放-获取有相同的内存效果(写==释放锁 ,读==获取锁)。
volatile 读/写的内存语义:当写一个volatile变量时,JMM会把对应的本地内存中的共享变量刷新到主存,实际是向接下来将要读取这个变量的某个线程发出消息。当读一个voltaile变量时,JMM会把该线程对应的本地缓存置为无效,线程接下来将从主存中读取共享变量。实际是接收到了之前某个线程发出的消息。因此volatile读/写实际是两个线程之间通过主存进行通信。
为了实现volatile的内存语义,JMM针对编译器制定了以下3条重排序规则,同时为了实现规则,JMM采取了如图1所示的内存屏障插入策略。
1、当第二个操作是volatile写时,不管第一个操作(volatile操作,普通操作)是什么,都不能重排序。
2、当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。
3、当第一个操作是volatile写,第二个操作是volatile读时,不能重排序。
图1
final域
对于final域,编译器和处理器遵守两条重排序规则:1、在构造函数内对一个final域的写入与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作不能重排序。2、初次读一个包含final域的对象的引用与随后初次读这个final域,这两个操作之间不能重排序。JMM禁止把final域的写重排序到构造函数之外,由此可保证在对象引用为任意线程可见之前,对象final域已经被正确初始化了(普通域不具有这个保障),当然前提条件是final引用不能从构造函数内“溢出”(对象未构造完成之前就将其引用暴露出去)。编译器会在final域写之后,构造函数返回之前插入StoreStore屏障,由此便确保了final域的写不会重排序到构造函数之外。通过为final域增加读/写重排序规则,可以为java程序员提供初始化安全保证:只要对象是正确初始化的(被构造对象的引用在s构造函数中没“溢出”),那么不需要同步就可以保证任意线程都能看到final域在构造函数中被初始化的值。
相关推荐
《JAVA并发编程实践》是一本深入探讨Java多线程编程技术的专业书籍,旨在帮助开发者理解和掌握在Java平台上进行高效并发编程的关键知识。本书涵盖了从基本概念到高级特性的全面内容,是Java程序员进阶的必读之作。 ...
本篇文章将深入探讨Java并发编程的相关知识点,主要基于提供的两个文件——"Java并发编程实战(中文版).pdf"和"Java Concurrency in Practice.pdf"。 1. **线程与并发** - **线程基础**:Java中的线程是并发执行...
首先,我们需要理解Java并发编程的基础——线程。在Java中,通过`Thread`类或者实现`Runnable`接口来创建线程。线程是程序执行的最小单位,允许多个任务在同一时间内执行。通过线程,我们可以实现并行处理,提升程序...
首先,我们要明白Java并发编程的基础——线程。线程是操作系统分配CPU时间的基本单位,Java通过`Thread`类提供了对线程的支持。创建线程主要有两种方式:继承`Thread`类和实现`Runnable`接口。理解线程的生命周期...
首先,我们要理解Java并发编程的基础——线程。线程是程序执行的最小单元,每个线程都有自己的程序计数器、虚拟机栈、本地方法栈等,而共享堆内存。在多核处理器系统中,多个线程可以同时运行,提升程序执行效率。 ...
### Java并发编程:volatile关键字解析 #### 一、内存模型的相关概念 在深入了解`volatile`关键字之前,我们首先需要理解计算机内存模型的一些基本概念。在现代计算机系统中,CPU为了提高执行效率,会将频繁访问的...
《Java并发编程艺术》这本书是Java开发者深入理解多线程编程的重要参考资料。它详细阐述了Java平台上的并发编程原理和实践技巧,旨在帮助开发者解决在多线程环境下遇到的各种复杂问题。 1. **并发基础** - **线程...
Java并发编程是软件开发中的重要领域,特别是在大型分布式系统和多核处理器环境下,高效地利用系统资源、提高程序性能及响应速度是至关重要的。本文将深入探讨Java并发编程的核心概念、方法与框架。 首先,我们要...
2. **书籍**:《Java并发编程实战》、《Concurrency in C++》等都是优秀的参考书目。 3. **官方文档**:查看不同编程语言的官方文档,了解并发编程的最佳实践。 4. **社区和论坛**:Stack Overflow、Reddit等社区...
通过这些脑图,学习者可以从宏观和微观两个层面理解并发编程,不仅能够掌握Java并发编程的基础知识,还能深入理解JVM内存模型和高级并发技术。每个脑图都是一张知识地图,引领学习者逐步探索并发编程的世界,虽然初...
为了确保Java程序能够在不同的操作系统和硬件平台上保持一致的行为,Java虚拟机(JVM)定义了一套统一的内存模型——Java Memory Model (JMM),它主要目的是为了消除不同平台下内存访问机制的差异性,使得Java程序可以...
总之,理解和掌握Java并发理论,包括线程安全、通信与同步、JMM以及并发工具,对于编写高效、稳定的多线程应用程序至关重要。开发者应关注并发编程的三大属性:原子性、有序性和可见性,并利用Java提供的并发机制来...
在Java并发编程中,这些规则确保了内存可见性和有序性,防止了数据竞争和脏读等并发问题。开发者可以通过synchronized关键字、volatile关键字、Atomic类等方式利用JMM来实现线程安全。理解并遵循这些规则是编写正确...
在准备深圳腾讯Java高级面试的过程中,你需要掌握一系列深入的Java编程和相关技术知识。这份压缩包文件"java面试——深圳-腾讯-Java高级.zip"包含了关键的面试指南,特别是对于那些寻求在大型科技公司如腾讯工作的...
在第三版中,作者可能会更新一些Java的新特性,比如Java集合框架的改进、泛型的引入、异常处理的优化以及并发编程的相关内容。 Java集合框架是Java API中非常重要的一部分,它提供了各种接口(如List、Set、Queue)...
9. **并发编程最佳实践**:提供一系列实用的并发编程技巧和最佳实践,以提高代码的可读性、可维护性和并发性能。 10. **Java内存模型**:深入解析Java内存模型(JMM),包括可见性、有序性和原子性,以及它们如何...
在并发编程领域,Volatile是Java中一个非常关键的特性,它为共享变量提供了内存可见性和有序性保证,但不保证原子性。本篇文章将深入分析Volatile的实现原理,结合`LinkedTransferQueue`和`TransferQueue`这两个与...
Java并发编程是软件开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发能力可以极大地提高程序性能。本章将通过“有福同享,有难同当—原子性”这一主题,深入探讨并发编程中的核心概念——原子性...
标题提及了两本书籍资源——"Scala程序设计(第2版).pdf"和"Scala程序设计-JAVA虚拟机多核编程实战.pdf",这表明主题聚焦在Scala编程语言以及其与Java虚拟机(JVM)多核编程的结合应用上。描述简单明了,确认了这两...
### 三问JMM——有关JVM内存模型的深度解析 #### 前言 近期,在诚信通开源研究小组的专题学习分享会上,我们针对Java内存模型(JMM)进行了深入探讨,现将JMM相关的一些核心概念进行梳理,以便更好地理解和把握JMM的...