Java内存模型以及线程安全的可见性问题是怎样的

发布时间:2021-11-20 14:13:10 作者:柒染
来源:亿速云 阅读:127

这期内容当中小编将会给大家带来有关Java内存模型以及线程安全的可见性问题是怎样的,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

Java内存模型 VS JVM运行时数据区

首先Java内存模型(JMM)和JVM运行时数据区并不是一个东西,许多介绍Java内存模型的文章描述的堆,方法区,Java虚拟机栈,本地方法栈,程序计数器这东西并不是Java内存模型的内容而是JVM运行时数据区的内容。
要理解二者的区别就要了解《Java虚拟机规范》和《Java语言规范》。我们知道Java虚拟机上并不知只有Java语言,像JRuby, ,Scala,Kotlin,Groovy等也都运行在Java虚拟机上,而这些语言想要在Java虚拟机上运行就要遵守《Java虚拟机规范》,而JVM运行时数据区就是《Java虚拟机规范》的内容。而《Java语言规范》就只是针对Java语言的规范,它对Java内存模型做了详细的描述。
Java内存模型以及线程安全的可见性问题是怎样的

什么是Java内存模型(JMM)?

要了解Java内存模型,首先要了解什么是内存模型,之间在CPU缓存和内存屏障 中我们了解到缓存一致性问题以及处理器优化的指令重排序问题。为了保证并发编程中可以满足原子性、可见性及有序性。有一个重要的概念,那就是——内存模型。它解决了 CPU 多级缓存、处理器优化、指令重排等导致的内存访问问题,保证了并发场景下的一致性、原子性和有序性。而Java内存模型就是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题的一种规范。目的是保证并发编程场景中的原子性、可见性和有序性。
Java内存模型可以分为线程栈(或者叫工作内存,它是每个线程所独有的)和堆(或者叫主内存,与JVM运行时数据区的堆并不是一个概念,它是所线程共享的),其大致逻辑图如下:
Java内存模型以及线程安全的可见性问题是怎样的

JMM中的具体内容

Shared Variables定义

可以在线程之间共享的内存称为共享内存或堆内存
所有实例字段,静态字段和数组元素都存储在共享内存,这些字段和数组就是共享变量
冲突:如果至少有一个访问是写操作,那么对同一个变量的两次访问是冲突的

这些能被多个线程访问的共享变量是内存模型规范的对象

线程间操作

线程间操作指一个线程执行的操作可被其他线程感知或被其他线程直接影响
Java内存模型只描述线程间操作,不描述线程内操作,线程内操作按照线程内语义执行
线程间操作有:

对同步规则的定义
happens-before先行发生原则

happens-before关系用于描述两个有冲突的动作之间的顺序,如果一个action happens before 另一个action,则第一个操作对第二个操作可见,JVM需要实现如下happens-before规则:

final在JMM中的处理

final在该对象的构造函数中设置对象的字段,当线程看到该对象时,将始终看到该对象的final字段的正确构造版本。如果在构造函数中设置字段后发生读取,则会看到该final字段分配的值,否则它将看到默认值。读取该对象的final成员变量之前,先要读取共享对象。
通常被 static final修饰的字段, 不能被修改。然而System.in, System.out, System.err被static final修饰却可以修改,遗留问题,必须通过set方法改变,我们将这些字段称为写保护,以区别于普通final字段。

Word Tearing字节处理

有些处理器(尤其是早期的Alphas处理器)没有提供写单个字节的功能。在这样的处理器上更新byte数组,若只是简单的读取整个内容,更新对应的字节,然后将整个内容再写回内存,将是不合法的。这个问题有时候被称为“字分裂(word tearing)”,更新字节有难度的处理器,就需要寻求其他方式来解决。因此,编程人员需要注意,尽量不要对byte[]中的元素进行重新赋值,更不要在多线程中这样做。

可见性问题

可见性:主要是指一个线程对共享变量的写入可以被后续另一个线程读取到,也就说一个线程对共享变量的操作对另一个线程是可见的。
而可见性问题就是指一个线程对共享变量进行了写入而其他的线程却无法读取到该线程写入的结果,根据以下工作内存的缓存的模型我们可以知道,造成可见性的问题主要有两方面,一个是数据在写入的时候只是写入了缓存而没有写入主内存,一个是数据在读取的时候只是从缓存中读取到了数据而没有从主内存读取数据。
Java内存模型以及线程安全的可见性问题是怎样的

可见性问题的解决方法 — volatile关键字

volatile关键字可以保证一个线程对共享变量的修改,能够及时的被其他线程看到。
根据JMM中的happen before 和同步原则:

上述就是小编为大家分享的Java内存模型以及线程安全的可见性问题是怎样的了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

推荐阅读:
  1. protected 可见性
  2. Java 高并发三 Java内存模型和线程安全详解

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:JavaScript的事件机制举例分析

下一篇:如何检测并避免 Java 中的死锁

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》