原子

并发数据结构:迷人的原子

为君一笑 提交于 2020-03-05 01:47:21
随着多核CPU成为主流,并行程序设计亦成为研究领域的热门。 要想利用多核/多路CPU带来的强大功能,通常使用多线程来开发应用程序。但是要想拥有良好的硬件利用率,仅仅简单的在多个线程间分割工作是不够的。还必须确保线程大部分时间在工作,而不是在等待工作或等待锁定共享数据结构。 在不止一个线程访问共享数据时,所有线程都必须使用同步。如果线程间不进行协调,则没有任务可以真正并行,更糟糕的是这会给程序带来毁灭性的错误。 现在让我们来看一下在.NET和D语言中的标准同步手段-锁定。.NET下我们使用lock关键字,而D语言则使用 synchronized关键字。它们在Windows下均使用临界区(Critical Section)来实现,而在Linux下则使用互斥锁(Mutex)来实现。不论其如何实现,它们均强制实行互斥,来确保持有锁的线程对共享数据的独占访问权,以及当其他线程持有锁时,可以看到其对共享数据的修改。 简而言之,在基于锁的多线程编程中,任何针对共享数据,且有可能导致竞争条件的操作,我们都得将其改为原子操作(即连续的,不允许被打断的步骤;上面的lock/ synchronized 关键字就是我们实现原子操作的手段)。只要我们的线程持有锁,就不必担心其他线程会进来捣乱。 这听起来似乎很不错,我们只要加锁/解锁就可以为所欲为了。然而正是这种为所欲为的事实带来了问题

多线程编程学习十二(原子性、可见性与有序性)

半城伤御伤魂 提交于 2020-03-04 10:19:11
原子性 原子(atom)指化学反应不可再分的基本微粒,原子在化学反应中不可分割。原子操作指的是不可分割的整体,多线程的 原子性 指的是没有其他线程能够中断或检查正在原子操作中的变量。 从内存模型来看,直接保证的原子性变量操作包括 read、load、assign、use、store 和 write,我们大致可以认为基本数据类型的访问读写是具备原子性的。 从应用场景来看,JVM 保证原子性操作的主要有以下方式: synchronized 关键字。锁操作,基于 monitorenter 和 monitorexit 字节码指令,保证同步块只有单一线程执行。 AQS 锁机制。比如 ReentrantLock、ReentrantReadWriteLock 等,保证同步块只有单一线程执行。 CAS 实现。比如 java.util.concurrent.atomic 包中的诸多实现。 volatile 关键字。修饰变量,轻量锁机制,仅能保证对单个变量的操作具有原子性,复合操作不具备原子性。 可见性 可见性 是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。 从应用场景来看,JVM 保证可见性主要有以下方式: volatile 关键字,它是如何保证可见性的呢? 当对 volatile 变量写的时候,会将当前处理器缓存行的数据写回到系统内存。 当对 volatile 变量读的时候

JAVA JUC

非 Y 不嫁゛ 提交于 2020-03-04 03:55:54
文章目录 JAVA JUC 一、Volatile 关键字-内存可见性 1、java线程的6种状态Thread.state: 2、JAVA多线程:判断 干活 改标志位加唤醒通知(详见Thread.start()方法) 3.一共两个线程 (1)同步锁:synchronized关键字,使两个线程同步 (2)Volatile关键字 (3)Volatile与Scnchronized比较 二、原子变量与CAS算法 1、i ++ 的原子性问题:i++ 的操作实际上分为三个步骤“读-改-写” 2、原子变量:JDK1.5以后 java.util.concurrent.atomic 包下提供了常用的原子变量 (1)原子变量特性 (2)原子性的解决过程:(先读取内存值,再进行比较,再进行赋值和写入) (3)原子变量的使用: 三、模拟CAS算法 四、ConcurrentHashMap锁分段机制 1、hashmap和hashtable区别: 2、ConCurrentHashMap采用“锁分段”机制 3、CopyOnWriteArrayList/CopyOnWriteArraySet : “写入并复制” 4、CountDownLatch(==闭锁==,在完成某些运算是,只有其他所有线程的运算全部完成,当前运算才继续执行) 四、创建执行线程的方式三:实现Callable接口 五、Lock同步锁 1

甄别烷烃基的类别

眉间皱痕 提交于 2020-03-03 23:48:02
问题描述: 化学很神奇,以下是烷烃基。 假设如上图,这个烷烃基有6个原子和5个化学键,6个原子分别标号1~6,然后用一对数字 a,b 表示原子a和原子b间有一个化学键。这样通过5行a,b可以描述一个烷烃基。你的任务是甄别烷烃基的类别。 input: 输入第一行为数据的组数T(1≤T≤200000)。每组数据有5行,每行是两个整数a, b(1≤a,b≤6,a ≤b),数据保证,输入的烷烃基是以上5种之一 output: 每组数据,输出一行,代表烷烃基的英文名 解题思路: 首先,对于输出,我们可以很容易的得到每一个原子相连几个化学键,然后通过观察分析,以上5中同分异构体可以分为4大类,通过与两个化学相连的原子个数有几个来分类,n-hexane有四个与两个化学键相连的原子,2,2-dimethylbutane有一个与两个化学键相连的原子,2,3-dimethylbutane不存在与两个化学键相连的原子,而其余两个,都有两个与两个化学键相连的原子,所以剩余的任务就是找到这两类的不同之处。 通过观察,我们发现 这两个结构在画红线的原子那里结构是不同的,一个与两个 有与两个化学键相连的原子 进行连接,而另一个只有一个,则我们可以通过它们相连的原子有几个是有两个化学键相连的来进行判断。 首先我们可以定义一个二维数组,来存储我们的输入,然后在输入的过程中,计算与两个化学相连的原子个数

6.并发编程--volatile

不问归期 提交于 2020-03-03 13:47:05
并发编程--volatile volatile-说明 volatile关键字的作用是变量在多个线程可见; volatile 关键字是非原子性的 要是实现原子性操作,建议使用atomic类的系列对象:支持原子性操作(注意atomic类只保证本身方法的原子性,并不保证多次操作的原子性) 1. volatile : volatile关键字的作用是变量在多个线程可见; 示例: RunThread.java 说明: 在Java中,每个线程都会有一个工作内存区域,其中存放所有线程共享的主内存中的变量的值得拷贝。当线程执行的时候,在自己的工作内存区域中操作这些变量。为了存取一个共享的变量,一个线程通常先获得锁定并清除当前线程的内存工作区域,把这些共享变量从所有线程的共享内存区域中正确的装入到本身所以在的工作内存区域中,当线程解锁是保证该工作内存中的变量的值写会到共享内存区域中。 * 一个线程可以执行的操作有:使用(use),赋值(assgin),装载(load),存储(store),锁定(lock),解锁(unlock); * 主内存中可以执行的操作有:读(read),写(write),锁定(lock),解锁(unlock); 每个操作都是原子性的。 * volatile 的作用就是强制线程到主内存(共享内存)中去读取变量,而不是去线程工作内存区域里去读取,从而实现了多个线程间的变量可见

操作系统-原子性与锁机制

让人想犯罪 __ 提交于 2020-03-03 02:39:21
原子性和锁机制 所谓原子性和原子操作即一条或者一系列不可以被中断的指令 原子性的保证: 单核CPU如何保证指令的原子性? 单核CPU下各个指令都是串行的,中断只会发生在一条指令执行完毕,那么自然每个指令都是原子的,如果想要实现单核CPU下多个指令的的原子操作,则可以通过关中断实现 多核CPU如何保证指令的原子性? 多核CPU下由于出现并发问题,所以多个核心可能同时读写同一个内存,所以需要通过一些机制来实现原子操作 多核CPU确保一条指令的原子性,例如递减指令,实际上是三个操作,先读取内存,递减,写回,但是由于是多核CPU,所以即便是一条指令,也无法保证原子性,所以多核总线是通过总线锁来实现多核CPU的原子性的,即在指令执行前先通过总线锁锁住CPU和内存的通信(CPU1向总线发出LOCK#信号,其他处理器便不可以再访问该共享的内存) 总线锁会锁住CPU和内存的通信,开销大(此时并行化的操作变成了串行化的操作,但是),所以可以使用缓存锁,并通过缓存一致性机制来保证原子操作,缓存一致性即MESI协议,介绍如下: 每个CPU有自己的高速缓存,高速缓存以缓存行的形式存在,而MESI就是给每个缓存行保存一个标志位,标志位如下: M:被修改的,当前缓存行中的数据相对内存而言已经被修改了,但是还没有更新到内存中,同时处于该状态的数据只有当前CPU缓存中有,而其他CPU缓存中没有 E:独占的

Hbase表类型的设计

爷,独闯天下 提交于 2020-03-02 21:00:37
HBase表类型的设计 1 、短宽 这种设计一般适用于: * 有大量的列 * 有很少的行 2、高瘦 这种设计一般适用于: * 有很少的列 * 有大量的行 3、短宽-高瘦的对比 短宽 * 使用列名进行查询不会跳过行或者存储文件 * 更好的原子性 * 不如高瘦设计的可扩展性 高瘦 * 如果使用ID进行查询,会跳过行 * 不利于原子性 * 更好的扩展 来源: https://www.cnblogs.com/alexzhang92/p/10941131.html

广义表的概念

核能气质少年 提交于 2020-03-01 08:22:23
广义表的概念  广义表(Lists,又称列表)是线性表的推广。即广义表中放松对表元素的原子限制,容许它们具有其自身结构。 1、广义表定义   广义表 是n(n≥0)个元素a 1 ,a 2 ,…,a i ,…,a n 的有限序列。 其中:  ①a i --或者是原子或者是一个广义表。    ②广义表通常记作: Ls=( a 1 ,a 2 ,…,a i ,…,a n )。    ③Ls是广义表的名字,n为它的 长度 。     ④若a i 是广义表,则称它为Ls的 子表 。 注意:  ①广义表通常用圆括号括起来,用逗号分隔其中的元素。  ②为了区分原子和广义表,书写时用大写字母表示 广义表 ,用小写字母表示 原子 。  ③若广义表Ls非空(n≥1),则a l 是LS的表头,其余元素组成的表(a 1 ,a 2 ,…,a n )称为Ls的表尾。   ④广义表是递归定义的 2、广义表表示 (1)广义表常用表示   ① E=()  E是一个空表,其长度为0。   ② L=(a,b)  L是长度为2的广义表,它的两个元素都是原子,因此它是一个线性表   ③ A=(x,L)=(x,(a,b))  A是长度为2的广义表,第一个元素是原子x,第二个元素是子表L。   ④ B=(A,y)=((x,(a,b)),y)   B是长度为2的广义表,第一个元素是子表A,第二个元素是原子y。   ⑤ C=(A,B

数据结构28:广义表及M元多项式

Deadly 提交于 2020-03-01 07:41:59
广义表,又称为列表。记作: LS = (a 1 ,a 2 ,…,a n ) ;( LS 为广义表的名称, a n 表示广义表中的数据)。 广义表可以看作是线性表的推广。两者区别是:线性表中的数据元素只能表示单个数据元素;广义表中的单个数据元素 a i ,既可以是单个元素,也可以是广义表。 原子和子表 在广义表中,单个元素被称为 “原子”;包含的广义表被称为 “子表”。 例如: A = () :A 表示一个广义表,只不过表是空的,广义表 A 的长度为 0。 B = (e) :广义表 B 中只有一个原子 e ,长度为 1。 C = (a,(b,c,d)) :广义表 C 中有两个元素,原子 a 和子表 (b,c,d) ,广义表C的长度为 2。 D = (A,B,C) :广义表 D 中有三个元素:子表 A、B、C,长度为 3 ,这种表示方式等同于: D = ((),(e),(b,c,d)) 。 E = (a,E) :广义表 E 中有两个元素,原子 a 和它本身,长度为 2 。这是一个递归的表,等同于:E = (a,(a,(a,…)))。 A = () 和 A = (()) 是不一样的:前者是空表,长度为 0 ;后者表的长度为 1 ,包含的元素是一个子表,只不过这个子表是空表。 表头和表尾 当广义表不为空时,称表中的第一个元素为表的 “表头” ;剩余所有元素组成的表为 “表尾” 。

代码面试之广义表

社会主义新天地 提交于 2020-03-01 06:57:57
广义表的基本概念 广义表(Lists,又称列表) 是线性表的推广。线性表定义为n>=0个元素a1,a2,a3,…,an的有限序列。线性表的元素仅限于原子项,原子是作为结构上不可分割的成分,它可以是一个数或一个结构,若放松对表元素的这种限制,容许它们具有其自身结构,这样就产生了广义表的概念。 广义表是n (n>=0)个元素a1,a2,a3,…,an的有限序列,其中ai或者是原子项,或者是一个广义表。通常记作LS=(a1,a2,a3,…,an)。LS是广义表的名字,n为它的长度。若ai是广义表,则称它为LS的子表。 抽象数据类型广义表的定义如下: ADT Glist { 数据对象: D={ei | i=1,2,..,n;n>=0 ; eiÎAtomSet 或ei ÎGlist, AtomSet为某个数据对象} 数据关系:R1={< ei-1, ei > | ei-1 , ei ÎD,2<=i<=n} 基本操作: InitGList( &L); 操作结果:创建空的广义表L。 CreateGList(&L,S); 初始条件:S是广义表的书写形式串。 操作结果:由S创建广义表L。 DestroyGList(&L); 初始条件:广义表L存在。 操作结果:销毁广义表L。 CopyGList( &T,L); 初始条件:广义表L存在。 操作结果:由广义表L复制得到广义表T。 GListLength