首页 > 其他分享 >并发总结

并发总结

时间:2023-07-10 11:34:18浏览次数:34  
标签:总结 缓存 synchronized 并发 线程 内存 执行 CPU

并发总结

Java多线程与并发

为什么出现并发问题

众所周知,CPU、内存、I/O 设备的速度是有极大差异的,为了合理利用 CPU 的高性能,平衡这三者的速度差异,计算机体系结构、操作系统、编译程序都做出了贡献,主要体现为:

  • CPU 增加了缓存,以均衡与内存的速度差异;// 导致 可见性问题
  • 操作系统增加了进程、线程,以分时复用 CPU,进而均衡 CPU 与 I/O 设备的速度差异;// 导致 原子性问题
  • 编译程序优化指令执行次序,使得缓存能够得到更加合理地利用。// 导致 有序性问题

可见性: CPU缓存引起

假若执行线程1的是CPU1,执行线程2的是CPU2。由上面的分析可知,当线程1执行 i =10这句时,会先把i的初始值加载到CPU1的高速缓存中,然后赋值为10,那么在CPU1的高速缓存当中i的值变为10了,却没有立即写入到主存当中。

此时线程2执行 j = i,它会先去主存读取i的值并加载到CPU2的缓存当中,注意此时内存当中i的值还是0,那么就会使得j的值为0,而不是10.

这就是可见性问题,线程1对变量i修改了之后,线程2没有立即看到线程1修改的值。

原子性: 分时复用引起

这里需要注意的是:i += 1需要三条 CPU 指令

  1. 将变量 i 从内存读取到 CPU寄存器;
  2. 在CPU寄存器中执行 i + 1 操作;
  3. 将最后的结果i写入内存(缓存机制导致可能写入的是 CPU 缓存而不是内存)。

由于CPU分时复用(线程切换)的存在,线程1执行了第一条指令后,就切换到线程2执行,假如线程2执行了这三条指令后,再切换会线程1执行后续两条指令,将造成最后写到内存中的i值是2而不是3。

有序性: 重排序引起

在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序。重排序分三种类型:

  • 编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
  • 指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
  • 内存系统的重排序。由于处理器使用缓存和读 / 写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。

JAVA是怎么解决的:JMM(Java内存模型)

JMM本质上可以理解为,Java 内存模型规范了 JVM 如何提供按需禁用缓存和编译优化的方法。具体来说,这些方法包括:

  • volatile、synchronized 和 final 三个关键字
  • Happens-Before 规则

可见性

Java提供了volatile关键字来保证可见性。

当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。

另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。

原子性

在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行。

Java内存模型只保证了基本读取和赋值是原子性操作,如果要实现更大范围操作的原子性,可以通过synchronized和Lock来实现。由于synchronized和Lock能够保证任一时刻只有一个线程执行该代码块,那么自然就不存在原子性问题了,从而保证了原子性。

有序性

在Java里面,可以通过volatile关键字来保证一定的“有序性”(具体原理在下一节讲述)。另外可以通过synchronized和Lock来保证有序性,很显然,synchronized和Lock保证每个时刻是有一个线程执行同步代码,相当于是让线程顺序执行同步代码,自然就保证了有序性。当然JMM是通过Happens-Before 规则来保证有序性的。

关键字: volatile详解

关键字: synchronized详解

线程基础知识

线程基础知识

CAS & AQS

标签:总结,缓存,synchronized,并发,线程,内存,执行,CPU
From: https://www.cnblogs.com/jiuxialb/p/17540460.html

相关文章

  • Java 并发
    Java并发线程基础进程线程概念进程是一个独立的运行环境,而线程是在进程中执行的一个任务。他们两个本质的区别是是否单独占有内存地址空间及其它系统资源(比如I/O):进程单独占有一定的内存地址空间,所以进程间存在内存隔离,数据是分开的,数据共享复杂但是同步简单,各个进程之间互......
  • 线段树学习笔记与总结
    线段树学习笔记与总结目录线段树引入资源链接模板线段树引入我们经常会遇到需要维护一个序列的问题,例如给定一个整数序列,每次操作会修改序列某个位置上的数,或是海间你序列巾某个区问内所有数的和,用“暴力"算法,单点修改的复杂度为\(O(1)\),询问区间和的单次复杂度为\(O(N)\)......
  • 新版Springboot3.0打造能落地的高并发仿12306售票系统
    第1章课程介绍与学习指南3节|22分钟本章主要对课程做整体介绍,其中包括:课程要解决的问题、课程特色和亮点、课程内容安排、学完大家的收获,以及在学习方法上提出的建议与指导。 第2章12306这个系统架构到底有多牛?8节|71分钟本章主要对课程为什么选择12306课程作为实战......
  • 每日总结2023年7月9日
    今日学习:idea基本快捷键和模板(fori和sout)的学习和练习,有了这些以后发现能大大的加快我的开发速度。巩固模式分解问题,相比于昨天能够做题,判断分解是否为无损分解;事务的特性:原子性、一致性、隔离性、持续性;并发问题:丢失更新、不可重复读、读“脏”数据。一级封锁协议:防止丢失修改。......
  • 学习总结:《代码中的软件工程》
    在学习过程中,我对《代码中的软件工程》这本书有了一些深入的理解,并结合本课程的学习内容,我想就一些亮点和个人见解进行总结。通过学习,可以系统掌握软件工程这门实践与理论相结合的学科;对于复习系统知识,进阶理论来说大有裨益,本书的框架如下,推荐大家参考和阅读:•【实践为主】工欲......
  • CQBZ周考六思想总结
    cqbz周考6总结第一题veryEZ,看到mod,又只是求数量,所以直接分段探讨(毕竟可以枚举b)就彳亍了   还是感谢样例让我看到了特殊情况第二题   是我很难受的,我写了一个plus版本的,交的时候交的是原版本的,痛失50pts   为什么是50pts,因为我找人的时候是O(n)的,当时忘记lower_......
  • Hash 学习笔记与总结
    Hash算法学习笔记与总结目录Hash字符串Hash信息学奥赛一本通AcWing模板模板题题目大意CODEHash表拉链法开放寻址法模板题题目大意CODEHash哈希算法是通过一个哈希函数H,将一种数据(包活字符串、较大的数等)转化为能够用变量表示或是直接就可作为数组下标的数,道过哈希函数......
  • 7.9总结
    今天上午起床后刷视频,看了会javaweb的知识,被其中软件的安装等等东西卡住了,然后就刷视频,睡觉。下午做pta,做了一点车票管理系统的框架,功能还在慢慢摸索,大约五点多,妈妈回家了,然后就和她一起去地里打药。两个人快了很多,一开始有点热,后来习惯了,回家后就吃饭,写博客。......
  • 7.09 周日总结
    今天学习了赋值运算符和关系运算符,四种逻辑运算符(与&,或|,异或^,取反!),短路逻辑运算符(&,|无论左边是否正确,右边都会执行;&&,||如果左边可以确定表达式结果,右边不会执行),三元运算符和运算符的优先级以及原码反码补码,完成了运算符部分的内容。并且复习了前面所讲的知识点,并根据所学内容......
  • 七月九日总结
    早上8点起床洗漱吃饭修养身体。中午吃完午饭午睡一会起来以后学习java,吃完晚饭洗漱,准备睡觉。明天继续修养身体,同时进行Java的进一步学习。睡觉时间较晚,需要早睡,学习时间需要进一步增多。......