资讯专栏INFORMATION COLUMN

多线程并发-计算机基础

JohnLui / 1270人阅读

摘要:缓存行也必须监听其它缓存使该缓存行无效或者独享该缓存行的请求,并将该缓存行变成无效。无注意对于和状态而言总是精确的,他们在和该缓存行的真正状态是一致的,而状态可能是非一致的。多线程并发的优势和缺点

CPU缓存一致性协议MESI

CPU在摩尔定律的指导下以每18个月翻一番的速度在发展,然而内存和硬盘的发展速度远远不及CPU。这就造成了高性能能的内存和硬盘价格及其昂贵。然而CPU的高度运算需要高速的数据。为了解决这个问题,CPU厂商在CPU中内置了少量的高速缓存以解决IO速度和CPU运算速度之间的不匹配问题。
在CPU访问存储设备时,无论是存取数据抑或存取指令,都趋于聚集在一片连续的区域中,这就被称为局部性原理。

时间局部性(Temporal Locality):如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。

比如循环、递归、方法的反复调用等。

空间局部性(Spatial Locality):如果一个存储器的位置被引用,那么将来他附近的位置也会被引用。

比如顺序执行的代码、连续创建的两个对象、数组等

带有高速缓存的CPU执行计算的流程

程序以及数据被加载到主内存

指令和数据被加载到CPU的高速缓存

CPU执行指令,把结果写到高速缓存

高速缓存中的数据写回主内存

多核CPU多级缓存一致性协议MESI

MESI协议缓存状态

缓存行(Cache line):缓存存储数据的单元。

状态 描述 监听任务
M 修改 (Modified) 该Cache line有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中。 缓存行必须时刻监听所有试图读该缓存行相对就主存的操作,这种操作必须在缓存将该缓存行写回主存并将状态变成S(共享)状态之前被延迟执行。
E 独享、互斥 (Exclusive) 该Cache line有效,数据和内存中的数据一致,数据只存在于本Cache中。 缓存行也必须监听其它缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行需要变成S(共享)状态。
S 共享 (Shared) 该Cache line有效,数据和内存中的数据一致,数据存在于很多Cache中。 缓存行也必须监听其它缓存使该缓存行无效或者独享该缓存行的请求,并将该缓存行变成无效(Invalid)。
I 无效 (Invalid) 该Cache line无效。

注意:
对于M和E状态而言总是精确的,他们在和该缓存行的真正状态是一致的,而S状态可能是非一致的。如果一个缓存将处于S状态的缓存行作废了,而另一个缓存实际上可能已经独享了该缓存行,但是该缓存却不会将该缓存行升迁为E状态,这是因为其它缓存不会广播他们作废掉该缓存行的通知,同样由于缓存并没有保存该缓存行的copy的数量,因此(即使有这种通知)也没有办法确定自己是否已经独享了该缓存行。

从上面的意义看来E状态是一种投机性的优化:如果一个CPU想修改一个处于S状态的缓存行,总线事务需要将所有该缓存行的copy变成invalid状态,而修改E状态的缓存不需要使用总线事务。

cpu多级缓存 - 乱序执行优化

处理器为提高运算速度儿做出违背代码原有顺序的优化。

在单核处理器时代处理器的乱序执行优化不会影响执行结果。在多核处理中,某个核心执行写入操作时,将某个标志当做写入完成,进行重排优化,可能会先执行标志指令导致其他核心以为改核心已经执行完成写入操作。从而拿到错误的值。
java内存模型(java memory model, JMM)

堆heap

堆是运行时确定的内存,由java GC来维护大小,优点是可以动态的确定大小,缺点是运行时动态确定内存所以速度相对栈小一点。对象存放在堆上。静态变量跟随类一起存放在堆上。

栈stack

栈内存的速度相对堆内存更快,仅次于寄存器,缺点是大小必须是编译期确定的。缺乏一定的灵活性,存放一些基本的数据变量(int double。。。)java内存要求本地变量(Local Variable),调用栈必须存放在线程栈(Thead Stack)中。

本地变量可能存放的是对象的引用。当两个线程同时引用一个对象时,那么这两个线程的本地引用存放的是这个对象的私有拷贝。

硬件内存模型如图

硬件内存模型和java内存模型的对应模型如图:


java内存抽象模型结构


看图,本地内存:本地内存是java抽象的概念,涵盖了缓存,写缓存区,寄存器,其他硬件和编译器优化。本地内存储存了共享变量的副本,从硬件的角度上讲主内存就是硬件内存,但是为了获取更好的速度,java可能会将数据存储在寄存器或者高速缓存区。如果线程要通信必须要经过主内存,流程是先在主内存中获取共享变量,存储在本地内存中经由进程计算,然后刷新至主内存,再经由其他线程访问。

java内存模型- 同步操作与规则

lock和Unlack:作用在主内存上只有在Unlock的情况下内存才可以被其他线程锁定。

Read:作用在主内存上,把主内存中的变量输送在工作内存中。

Load:作用工作内存中,把主内存中的值放入到工作内存副本中。

use:作用于工作内存,把数据给执行引擎。每当执行器需要使用到变量时或者执行字节码指令时会执行这个操作。

assign:赋值,在执行赋值操作时执行,将执行引擎中的值赋值给工作内存。

store:存储,把工作内存中的值传递到主内存中。

write:写入,将工作内存中的值写入到主内存中。

下面介绍一下规则,规则是用来限制每一步是如何操作的。

不允许read和load、store和write单一出现,因为他们是一个连贯的操作。而且必须是按顺序执行的。load必须是read之后,write必须是store之后,但是不一定是连续操作,在他们之间可以插入其他的指令。

不允许线程丢弃assign操作,也就是说执行完了之后必须放入工作内存中。

不允许线程不经过Assign操作直接把数据给主内存。

一个新的变量只能在主内存中诞生。

一个变量只允许一个线程对其lack操作,但是可以被一个线程lack多次,lack多次之后只有执行相同次数的unlack才能被解锁。

如果一个变量执行了lack操作之后将会清楚工作内存中该变量的值。执行引擎在使用变量时需要重新执行read-load-use等操作。

如果没有执行一个lack操作的变量不能执行unlack操作。或者被其他线程执行了lack操作的线程也不能被改线程执行unlack。

多线程并发的优势和缺点

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73328.html

相关文章

  • 线程编程完全指南

    摘要:在这个范围广大的并发技术领域当中多线程编程可以说是基础和核心,大多数抽象并发问题的构思与解决都是基于多线程模型来进行的。一般来说,多线程程序会面临三类问题正确性问题效率问题死锁问题。 多线程编程或者说范围更大的并发编程是一种非常复杂且容易出错的编程方式,但是我们为什么还要冒着风险艰辛地学习各种多线程编程技术、解决各种并发问题呢? 因为并发是整个分布式集群的基础,通过分布式集群不仅可以大...

    mengera88 评论0 收藏0
  • 线程三分钟就可以入个门了!

    摘要:系统级线程核心级线程由操作系统内核进行管理。值得注意的是多线程的存在,不是提高程序的执行速度。实现多线程上面说了一大堆基础,理解完的话。虚拟机的启动是单线程的还是多线程的是多线程的。 前言 之前花了一个星期回顾了Java集合: Collection总览 List集合就这么简单【源码剖析】 Map集合、散列表、红黑树介绍 HashMap就是这么简单【源码剖析】 LinkedHashMa...

    awkj 评论0 收藏0
  • Python基础之使用期物处理并发

    摘要:本文重点掌握异步编程的相关概念了解期物的概念意义和使用方法了解中的阻塞型函数释放的特点。一异步编程相关概念阻塞程序未得到所需计算资源时被挂起的状态。 导语:本文章记录了本人在学习Python基础之控制流程篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。 本文重点: 1、掌握异步编程的相关概念;2、了解期物future的概念、意义和使用方法;3、了解Python...

    asoren 评论0 收藏0
  • Java 线程编程基础——Thread 类

    摘要:程序执行时,至少会有一个线程在运行,这个运行的线程被称为主线程。程序的终止是指除守护线程以外的线程全部终止。多线程程序由多个线程组成的程序称为多线程程序。线程休眠期间可以被中断,中断将会抛出异常。 线程 我们在阅读程序时,表面看来是在跟踪程序的处理流程,实际上跟踪的是线程的执行。 单线程程序 在单线程程序中,在某个时间点执行的处理只有一个。 Java 程序执行时,至少会有一个线程在运行...

    zhoutk 评论0 收藏0

发表评论

0条评论

JohnLui

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<