暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Java并发与高并发解决方案(一)

程序员雨衣 2019-05-18
172

一:并发与⾼并发基本概念

    并发

    同时拥有 2 个或多个线程,如果程序在单核处理器上运行,多个线程将交替地换入或者换出内存,这些线程是同时“存在”的,每个线程都处于执行过程中的某个状态;如果运行在多核处理器上,此时,程序中的每个线程都将分配到一个处理器核上,因此可以同时运行。

    
    ⾼并发
    高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,
通过设计保证系统能够同时并行处理很多请求

    
    并发与⾼并发    

    人们谈论并发,一般关注的是:多个线程操作相同的资源,如何保证线程安全,如何合理使用资源
    人们谈论高并发,一般关注的是:如何让服务同时处理很多请求,如何提高程序性能


二:并发基础

    2.1CPU 多级缓存-缓存⼀致性

        2.1.1CPU 多级缓存

如图, 数据的读取和存储都经过高级缓存; CPU 核心和高速缓存之间有一条特殊的高速通道;主存和高速缓存都连在系统总线上,该总线还用于其他主要的通信。

在告诉缓存出现后不久,系统变得更加复杂,高速缓存和主存之间的速度差异被拉大,直到加入了另一级的缓存。新加入的这级缓存比第一级缓存更大,但是更慢;由于加大一级缓存从经济上是行不通的,所以有了二级缓存;甚至有些系统有三级缓存。 


2.1.2 为什么需要 CPU 缓存?
    因为 CPU 的频率太快了,快到主存跟不上。这样,在处理器时钟周期内, CPU 常常需要等待主存,浪费资源。所以 cache 的出现,是为了缓解 CPU 和内存之间的速度不匹配问题(结构: CPU -> cache -> memory)


2.1.3 CPU 缓存有什么意义?
    1. 时间局部性:如果某个数据被访问,那么在不久的将来它很可能被再次访问
    2. 空间局部性:如果某个数据被访问,那么与它相邻的数据很快也可能被访问


2.1.4 缓存⼀致性(MESI)
    用于保证多个 CPU cache 之间缓存共享数据的一致

MESI 状态转换图

状态之间的相互转换关系也可以使用下表进行表示:

参考文档:
链接一:https://www.cnblogs.com/shangxiaofei/p/5688296.html

链接二:https://blog.csdn.net/muxiqingyang/article/details/6615199


2.2CPU 多级缓存-乱序执⾏优化
    在多核 CPU 中,乱序执行优化有可能会带来并发问题


2-3 JAVA 内存模型


    2.3.1 JAVA 内存模型

    Java 内存模型是一个规范, 它规范了 java 虚拟机是如何与计算机内存协同工作的。 它规定了一个线程如何以及何时能够看到其他线
程修改过的共享变量的值, 以及在必须时,如何同步地访问共享变量。

堆的优势:可以动态分配大小,生存期无需事先告诉编译器需要多少内存,因为是自动分配的。缺点是:由于需要动态分配内存,所以速度会慢一些。

栈的优势:存取速度比堆要快,仅次于寄存器。 缺点是:数据大小、生存期必须是确定的,缺乏灵活性。


    2.3.2 计算机硬件架构图⽰

CPU Register: CPU 在寄存器上执行的速度远大于在主存上执行的速度,因为 CPU 访问寄存器的速度远大于访问主存。
CPU Cache Memory:高速缓存。 比寄存器慢一点。


    2.3.3 内存模型抽象结构图

    

Java 中的工作内存,是对 CPU 内存中的寄存器、高速缓存的抽象的描述 


    2.3.4 同步的⼋种操作

    

1. lock-锁定:作用于主内存的变量,把一个变量标识为一条线程独占状态
2. unlock-解锁:作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
3. read-读取:作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的 load 动作使用
4. load-载入:作用于工作内存的变量,它把 read 操作从主内存中得到的变量值放到工作内存的变量副本中
5. use-使用:作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎
6. assign-赋值:作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量
7. store-存储:作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的 write 操作
8. write-写入:作用于主内存的变量,它把 store 操作从工作内存一个变量的值放入到主内存的变量中 


2.3.4.1 个⼈理解: readload 的区别
1. read 是把变量从 shared memory 读入 CPU local memory,或者说从内存读入 CPU cachewrite 反之
2. load 是把变量从 CPU local memory 读入 JVM stack,你可以认为它是把数据从 CPU cache 读入到“JVM 寄存器”, store 反之
3. 个人的理解: read 是一个 copy 操作,从主存拷贝对象到工作内存; load 就相当于把工作内存的对象和栈上的引用建立连接。
4. 参考: https://segmentfault.com/q/1010000000697450 


2.3.5 同步规则
1. 如果要把一个变量从主内存中复制到工作内存,就需要按顺序地执行 read load 操作,如果把变量从工作内存中同步回主内存
中,就要按顺序地指定
store write 操作。但 Java 内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行
2. 不允许 read loadstore write 操作之一单独出现
3. 不允许一个线程丢弃它最近的 assign 操作,即变量在工作内存中改变了之后必须同步到主内存中
4. 不允许一个线程无原因地(没有发生过任何 assign 操作)把数据从工作内存同步回主内存中
5. 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load assign)的变量。也就是对一个变量
实施
use store 操作之前,必须先执行过了 assign load 操作
6. 如果对一个变量执行 lock 操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行 load assign 操作
初始化变量的值。
7. 如果一个变量实现没有被 lock 操作锁定,则不允许对它执行 unlock 操作,也不允许去 unlock 一个被其他线程锁定的变量
8. 对一个变量执行 unlock 操作之前,必须先把此变量同步到主内存中(执行 store write 操作)
参考文档:
https://blog.csdn.net/gaowenhui2008/article/details/49759595


2.4 并发的优势与⻛险



文章转载自程序员雨衣,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论