原子操作

java并发之内存模型

百般思念 提交于 2019-12-01 07:03:24
java内存模型知识导图 一 并发问题及含义 并发编程存在原子性、可见性、有序性问题。 原子性即一系列操作要么都执行,要么都不执行。 可见性,一个线程对共享变量的修改,另一个线程可能不会马上看到。由于多核CPU,每个CPU核都有高速缓存,会缓存共享变量,某个线程对共享变量的修改会改变高速缓存中的值,但却不会马上写入内存。另一个线程读到的是另一个核缓存的共享变量的值,出现缓存不一致问题。 有序性,即程序执行的顺序按照代码的先后顺序执行。编译器和处理器会对指令进行重排,以优化指令执行性能,重排不会改变单线程执行结果,但在多线程中可能会引起各种各样的问题。 二 内存模型 为了保证共享内存的正确性(可见性、有序性、原子性),内存模型定义了共享内存系统中多线程程序读写操作行为的规范。内存模型解决并发问题 主要采用两种方式:限制处理器优化和使用内存屏障。 顺序一致性内存模型是一种理论参考模型,提供了极强的内存可见性保证,具有两大特性: 一个线程的所有操作按照程序的顺序执行,而不能重排序。 所有线程只能看到单一的执行顺序。每个操作都必须原子执行且立刻对其它线程可见。 顺序一致性内存模型禁止很多处理器和编译器重排,影响执行性能,处理器内存模型和JMM对顺序一致性内存模型进行放松,执行性能:处理器内存模型>JMM>顺序一致性内存模型,易编程性:处理器内存模型<JMM<顺序一致性内存模型。 三

Sword C语言原子操作

故事扮演 提交于 2019-12-01 07:03:15
/* gcc内置原子操作 */ #include <stdio.h> /* 知识补充: gcc 4.1.2版本之后,对X86或X86_64支持内置原子操作。即不需要引入第三方库(如pthread)的锁保护 ,即可对1、2、4、8字节的数值或指针类型,进行原子加/减/与/或/异或等操作 原子操作的本质目的是:再多线程场景下,不加锁的前提下,安全的实现对数值类型进行 加/减/与/或/异 操作 API type __sync_fetch_and_add (type *ptr, type value, ...) //将value加到*ptr上,结果更新到*ptr,并返回操作之前*ptr的值 type __sync_fetch_and_sub (type *ptr, type value, ...) // 从*ptr减去value,结果更新到*ptr,并返回操作之前*ptr的值 type __sync_fetch_and_or (type *ptr, type value, ...) // 将*ptr与value相或,结果更新到*ptr, 并返回操作之前*ptr的值 type __sync_fetch_and_and (type *ptr, type value, ...) // 将*ptr与value相与,结果更新到*ptr,并返回操作之前*ptr的值 type __sync_fetch

读书笔记《C++并发编程实战》(7) - 无锁的并发数据结构

 ̄綄美尐妖づ 提交于 2019-12-01 02:11:07
无锁数据结构: 不使用锁就能实现安全并发地存取的数据结构,可避免数据竞争、死锁、或锁引起性能限制等,以实现最大程度的提高并发性。 设计正确的无锁或无等待的数据结构是比较困难的,若确定需要无锁的情况下产生的收益高于代价时才应考虑(这个需要在多各方面考虑)。 无锁数据结构优缺点: 优点: 1. 最大限度的提高并发性,减少了线程等待的时间; 2. 提高健壮性,避免锁机制引入可能导致的数据结构损坏。 缺点: 1. 为了确保持有不变量或者选择可以持有的替代不变量需要加上操作上的顺序问题,需要加上原子操作,以确保正确的顺序对其他线程可见, 使得设计无锁数据结构比使用锁的更为困难。 2. 无锁可能导致性能下降,原子操作可能比非原子操作慢,无锁数据结构可能需要更多的原子操作,此外硬件在存取相同的原子变量的线程间 同步数据。 来源: https://www.cnblogs.com/haomiao/p/11647411.html

Java内存模型详解

喜欢而已 提交于 2019-11-30 18:21:53
Java内存模型详解 前几天,发了一篇文章,介绍了一下 JVM内存结构、Java内存模型以及Java对象模型之间的区别 。有很多小伙伴反馈希望可以深入的讲解下每个知识点。Java内存模型,是这三个知识点当中最晦涩难懂的一个,而且涉及到很多背景知识和相关知识。 网上有很多关于Java内存模型的文章,在《深入理解Java虚拟机》和《Java并发编程的艺术》等书中也都有关于这个知识点的介绍。但是,很多人读完之后还是搞不清楚,甚至有的人说自己更懵了。本文,就来整体的介绍一下Java内存模型,目的很简单,让你读完本文以后,就知道到底Java内存模型是什么,为什么要有Java内存模型,Java内存模型解决了什么问题等。 本文中,有很多定义和说法,都是笔者自己理解后定义出来的。希望能够让读者可以对Java内存模型有更加清晰的认识。当然,如有偏颇,欢迎指正。 为什么要有内存模型 在介绍Java内存模型之前,先来看一下到底什么是计算机内存模型,然后再来看Java内存模型在计算机内存模型的基础上做了哪些事情。要说计算机的内存模型,就要说一下一段古老的历史,看一下为什么要有内存模型。 内存模型,英文名Memory Model,他是一个很老的老古董了。他是与计算机硬件有关的一个概念。那么我先给你介绍下他和硬件到底有啥关系。 CPU和缓存一致性 我们应该都知道,计算机在执行程序的时候

Java内存模型

我怕爱的太早我们不能终老 提交于 2019-11-30 14:25:20
为什么要有内存模型 在介绍Java内存模型之前,先来看一下到底什么是计算机内存模型,然后再来看Java内存模型在计算机内存模型的基础上做了哪些事情。要说计算机的内存模型,就要说一下一段古老的历史,看一下为什么要有内存模型。 内存模型,英文名Memory Model,他是一个很老的老古董了。他是与计算机硬件有关的一个概念。那么我先给你介绍下他和硬件到底有啥关系。 CPU和缓存一致性 我们应该都知道,计算机在执行程序的时候,每条指令都是在CPU中执行的,而执行的时候,又免不了要和数据打交道。而计算机上面的数据,是存放在主存当中的,也就是计算机的物理内存啦。 刚开始,还相安无事的,但是随着CPU技术的发展,CPU的执行速度越来越快。而由于内存的技术并没有太大的变化,所以从内存中读取和写入数据的过程和CPU的执行速度比起来差距就会越来越大,这就导致CPU每次操作内存都要耗费很多等待时间。 这就像一家创业公司,刚开始,创始人和员工之间工作关系其乐融融,但是随着创始人的能力和野心越来越大,逐渐和员工之间出现了差距,普通员工原来越跟不上CEO的脚步。老板的每一个命令,传到到基层员工之后,由于基层员工的理解能力、执行能力的欠缺,就会耗费很多时间。这也就无形中拖慢了整家公司的工作效率。 可是,不能因为内存的读写速度慢,就不发展CPU技术了吧,总不能让内存成为计算机处理的瓶颈吧。 所以

原子性atomic/nonatomic

不想你离开。 提交于 2019-11-30 03:27:49
原子性:并发编程中确保其操作具备整体性,系统其它部分无法观察到中间步骤,只能看到操作前后的结果。 决定编译器生成的getter和setter是否原子 (natomic) 操作。 i 因此, atomic 效率较低,因为要保证操作完整,线程相对安全; nonatomic 不加同步,多线程并发访问效率高,但线程不安全。 由于锁定机制开销较大,一般 iOS 开发中会使用 nonatomic。 atomic 也不是绝对的线程安全。当多个线程同时调用 setter 和 getter 时,就会导致获取的值不一样。 兼顾线程安全和效率的方案 要想线程绝对安全,就要使用 @synchronized 同步锁。 // 同步锁 -(NSString *)name{ @synchronized(self) { return _name; } } -(void)setName:(NSString *)name{ @synchronized(self) { _name = name; } } 但是由于同步锁有等待操作,会降低代码效率。 为了兼顾线程安全和提升效率,可采用 GCD 并发队列进行优化。getter 使用同步派发,setter 使用异步栅栏。 // 并发队列 _queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

Java-CAS 与原子类

£可爱£侵袭症+ 提交于 2019-11-30 02:17:53
CAS(Compare and Swap),即比较并替换,实现并发算法时常用到的一种技术。 CAS 的思想很简单:三个参数,一个当前内存值 V、旧的预期值 A、即将更新的值 B,当且仅当预期值 A 和内存值 V 相同时,将内存值修改为 B 并返回 true,否则什么都不做,并返回 false。 和 CAS 相关的一个概念是原子操作。原子操作是不可被中断的一个或一系列操作。而 CAS 则是 Java 中保证原子操作的一种方式。 从 Java1.5 开始,JDK 的并发包里就提供了一些类来支持原子操作,都是以 Atomic 开头。 volatile 不能保证类似 i++ 这样操作的原子性,CAS 能够保证。 一、原子类使用 以 AtomicInteger 为例,常用 API: public final int get():获取当前的值 public final int getAndSet(int newValue):获取当前的值,并设置新的值 public final int getAndIncrement():获取当前的值,并自增 public final int getAndDecrement():获取当前的值,并自减 public final int getAndAdd(int delta):获取当前的值,并加上预期的值 相比 Integer 的优势,多线程中让变量自增:

Java多线程之原子操作类

北战南征 提交于 2019-11-30 00:08:55
在并发编程中很容易出现并发安全问题,最简单的例子就是多线程更新变量i=1,多个线程执行i++操作,就有可能获取不到正确的值,而这个问题,最常用的方法是通过Synchronized进行控制来达到线程安全的目的。但是由于synchronized是采用的是悲观锁策略,并不是特别高效的一种解决方案。实际上,在J.U.C下的Atomic包提供了一系列的操作简单,性能高效,并能保证线程安全的类去更新多种类型。Atomic包下的这些类都是采用乐观锁策略CAS来更新数据。 CAS原理与问题 CAS操作(又称为无锁操作)是一种乐观锁策略。它假设所有线程访问共享资源的时候不会出现冲突,因此不会阻塞其他线程的操作。那么,如果出现冲突了怎么办?无锁操作是使用CAS(compare and swap)来鉴别线程是否出现冲突,出现冲突就重试当前操作直到没有冲突为止。 CAS的操作过程 举例说明: Atomic包中的AtomicInteger类,是通过Unsafe类下的native函数compareAndSwapInt自旋来保证原子性, 其中incrementAndGet函数调用的getAndAddInt函数如下所示: public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this

第十二章 Java内存模型与线程

▼魔方 西西 提交于 2019-11-29 19:11:47
概述 并发应用场景:①充分利用计算机处理器的能力;②一个服务端同时为多个客户端提供服务。 衡量一个服务性能的高低好坏,每秒事务处理数是最重要的指标之一。 硬件的效率与一致性 Java内存模型 主内存和工作内存 ①Java内存模型的主要目标是定义程序中各个变量的访问规则 – 虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量(Variables)包括了实例字段、静态字段和构成数组对象的元素,但不包括局部变量与方法参数,因为后者是线程私有的,不会被共享,自然就不会存在竞争问题。 ②Java内存模型并没有限制执行引擎使用处理器的特定寄存器或缓存来和主内存进行交互,也没有限制即时编译器进行调整代码执行顺序这类优化措施。 ③Java内存模型规定了所有的变量都存储在主内存(Main Memory,类比物理内存)。每条线程还有自己的工作内存(Working Memory,类比处理器高速缓存),线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝。线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成,线程、主内存、工作内存三者的交互关系如图所示。 内存间相互操作 一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节

十、多线程控制类(1)

一笑奈何 提交于 2019-11-29 12:30:45
前言:   前面我们介绍了要想保证多线程变现过程中的安全问题,我们就要保证在读线程编写过程中保证多线程的三大特性,那么java为了保证多线程的三大特性引入了很多线程控制机制,下面就来介绍场用的几种。 一、ThreadLocal:    ThreadLocal线程本地变量,它可以为每一个线程刚保存一份线程内变量的副本,可以保证线程线程之间的变量时互不影响的,且是原子类可以保证变量的原子操作,当某些数据是以线程为作用域且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。   ThreadLocal常用的方法:     initialValue:创建副本方发: (注:在jdk1.8引入了lambda构造方式,方法变成了withlnitial)     get:获取副本方法:     set:设置副本方法:   在这里我我们来模拟一下两个用户之间的转账,来看一下ThreadLocal的实现: public class ThreadLocalDemo { //创建一个银行账户:账户有存款,可以进行存钱取钱操作。 static class Bank{ private ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> { return 0; //假设我们每个人的账户初始余额都是零 }); /