IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 多线程的三大特性 -> 正文阅读

[Java知识库]多线程的三大特性

目录

上下文切换

并行和并发的区别

?并发三大特性(一) 可见性

?并发三大特性(二) 原子性

?并发三大特性(三) 有序性

volatile介绍

jvm层面内存屏障


上下文切换

概念:当因为某些原因造成cpu不再执行当前线程,转去执行另一个线程,就会发生上下文切换。当发生上下文切换时,操作系统会保存当前线程的状态,并且恢复另一个线程的状态。保存当前线程状态时就会涉及到JVM的一个内存结构:程序计数器(Program Counter Register),它是线程私有的,用于记录当前线程要执行的下一条命令的地址。

发生上下文切换的时机:

  • 线程的时间片用完了
  • 垃圾回收
  • 线程中调用?sleep、yield、wait、join、park、synchronized、lock等方法

当发生上下文切换的时候,被恢复的线程读取的共享数据是从堆中读取的,而不是从本地变量副本读取

并行和并发的区别

并行:指在同一时刻,多条指令在多个cpu上同时执行,不论时微观还是宏观上看,都是同时执行

?并发:指多条指令在一个cpu上交替执行,同一时刻只能有一条指令在执行。但是由于交替的时间间隔很短,看不出来,所有宏观上来看是同时执行的,而微观上来看是分开交替执行的

?并发三大特性(一) 可见性

不可见性概念:当A线程修改了共享数据时,B线程没有及时获取到最新的值,如果还在使用原先的值,就会某些不可预期的问题

不可见原理:

?如图所示,共享数变量储在堆内存当中,而堆内存是唯一的,每个线程又有自己的线程栈,当线程要读取共享变量的时候,会先从堆内存中读取一份到线程栈中的变量副本中,之后读取该变量的时候会优先读取变量副本。而线程A在修改变量副本之后,会将堆中的共享变量的值进行更替,此时A的变量副本与堆内存中的共享变量都是最新的值,但是,线程B仍然读取的是之前的变量副本,两个线程读到的值就有所不同,这个的条件也相对苛刻,因为如果时间间隔较长不使用副本变量,就会对副本变量进行回收,然后下次读取还是会读取堆中的值。

可见性概念:当一个线程修改了共享变量的值,其他线程能够看到修改的值。

保证可见性的方式:

  • 通过 volatile 关键字保证可见性。
  • 通过 内存屏障保证可见性(Unsafe.getUnsafe().storeFence())
  • 通过 synchronized 关键字保证可见性。
  • 通过 Lock保证可见性。

以上几种都是通过内存屏障实现

  • 上下文切换
  • 通过 final 关键字保证可见性

猜测也是使用内存屏障实现的,顺便提一下Integer也可以实现可见性,因为内部也是使用final修饰。

?并发三大特性(二) 原子性

原子性问题

例如i++等操作执行过程是这样的,首先要先拿到内存中的数据,然后再保存到变量副本中,这时候在修改变量副本的值,然后再把变量副本的值替换掉内存中的值,在这个运算过程中走了三个步骤,在多线程环境中,可能修改好变量副本了,准备要往内存中复制这个过程中,就被其他线程修改了值,这时候再去复制,就导致结果最终不一致

解决方法:

  • 通过 synchronized 关键字保证原子性。
  • 通过 Lock保证原子性。
  • 通过 CAS保证原子性。

?并发三大特性(三) 有序性

有序性问题:

JVM?会在不影响正确性的前提下,可以调整语句的执行顺序(指令重排),思考下面问题

图中左侧是 3 行 Java 代码,右侧是这 3 行代码可能被转化成的指令。可以看出 a = 100 对应的是 Load a、Set to 100、Store a,意味着从主存中读取 a 的值,然后把值设置为 100,并存储回去,同理, b = 5 对应的是下面三行 ?Load b、Set to 5、Store b,最后的 a = a + 10,对应的是 Load a、Set to 110、Store a。如果你仔细观察,会发现这里有两次“Load a”和两次“Store a”,说明存在一定的重排序的优化空间。

重排序后, a 的两次操作被放到一起,指令执行情况变为 Load a、Set to 100、Set to 110、 Store a。下面和 b 相关的指令不变,仍对应 Load b、 Set to 5、Store b。

可以看出,重排序后 a 的相关指令发生了变化,节省了一次 Load a 和一次 Store a。重排序通过减少执行指令,从而提高整体的运行速度,这就是重排序带来的优化和好处
?

但是在多线程情况下,就会发生一些不可预期的事情!

?解决方法:

通过 volatile 关键字保证有序性。
通过 内存屏障保证有序性。
通过 synchronized关键字保证有序性。
通过 Lock保证有序性。

volatile介绍

valotile的作用:

可见性:对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

有序性:对volatile修饰的变量的读写操作前后加上各种特定的内存屏障来禁止指令重排序来保障有序性。

volatile写-读的内存语义
  • 当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。
  • 当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,线程接下来将从主内存中读取共享变量

1. 在每个volatile写操作的前面插入一个StoreStore屏障
2. 在每个volatile写操作的后面插入一个StoreLoad屏障
3. 在每个volatile读操作的前面插入一个LoadLoad屏障
4. 在每个volatile读操作的后面插入一个LoadStore屏障

volatile禁止重排序场景:
  • 第二个操作是volatile写,不管第一个操作是什么都不会重排序
  • 第一个操作是volatile读,不管第二个操作是什么都不会重排序
  • 第一个操作是volatile写,第二个操作是volatile读,也不会发生重排序

valotile的实现方式:

volatile在jvm层面上的实现是通过一个storeload内存屏障

在linux的x86系统中可以看到volatile的实现它实际上是调用汇编语言的lock前缀指令实现可见性的,它会使副本变量失效,强制性的要求下一次访问要从堆中获取最新的值。

?lock前缀指令的作用:

1. LOCK前缀指令具有类似于内存屏障的功能,禁止该指令与前面和后面的读写指令重排
序。
2. LOCK前缀指令会 等待它之前所有的指令完成、并且所有缓冲的写操作写回内存 (也就是将store buffer中的内容写入内存)之后才开始执行,并且根据缓存一致性协议,刷新store buffer的操作会导致其他cache中的副本失效

jvm层面内存屏障

在JSR规范中定义了4种内存屏障:
LoadLoad屏障 (指令Load1; LoadLoad; Load2),在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
LoadStore屏障 (指令Load1; LoadStore; Store2),在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
StoreStore屏障 (指令Store1; StoreStore; Store2),在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
StoreLoad屏障 (指令Store1; StoreLoad; Load2), 在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。 它的开销是四种屏障中最大的。在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-18 15:50:19  更:2021-12-18 15:51:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 12:42:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码