原子操作

volatile关键字

吃可爱长大的小学妹 提交于 2020-01-28 20:42:38
一、简介 volatile是Java提供的一种轻量级的同步机制。Java 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量,相比于synchronized(synchronized通常称为重量级锁),volatile更轻量级,因为它不会引起线程上下文的切换和调度。但是volatile 变量的同步性较差(有时它更简单并且开销更低),而且其使用也更容易出错。 二、并发编程的3个基本概念 (1)原子性 ​ 定义: 即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。 ​ 原子性是拒绝多线程操作的,不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作。简而言之,在整个操作过程中不会被线程调度器中断的操作,都可认为是原子性。例如 a=1是原子性操作,但是a++和a +=1就不是原子性操作。Java中的原子性操作包括: ​ a. 基本类型的读取和赋值操作,且赋值必须是数字赋值给变量,变量之间的相互赋值不是原子性操作。 ​ b.所有引用reference的赋值操作 ​ c.java.concurrent.Atomic.* 包中所有类的一切操作 (2)可见性 ​ 定义: 指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。 ​ 在多线程环境下

Java 原子操作类(atomic包)

十年热恋 提交于 2020-01-28 11:00:24
专栏原创出处: github-源笔记文件 , github-源码 ,欢迎 Star,转载请附上原文出处链接和本声明。 原子操作类说明 当程序更新一个变量时,如果是多线程同时更新这个变量,可能得到的结果与期望值不同。我们可以用 并发关键字-volatile 、 并发关键字-synchronized 、 Lock 来解决并发读写问题。 但是从性能及语义上可能存在以下问题: volatile 不能保证组合操作的原子性(比如自增操作) synchronized 和 Lock 比较重量级 从 java1.5 开始,jdk 提供了 java.util.concurrent.atomic 包,这个包中的原子操作类,提供了一种用法简单,性能高效,线程安全的更新一个变量的方式。 atomic 包里提供原子更新类型分别是:原子更新基本类型,原子更新数组,原子更新引用,原子更新属性,这些类都是使用 Unsafe 实现的包装类。 目前 jdk1.8 , Atomic 开头的原子类,提供的方法、处理逻辑基本一致。差异部分表现在非数值类型的原子类支持自增自减操作。 jdk1.8 中新增了高性能原子类,参考《高性能原子类》一节介绍。 原子更新基本类型 Atomic 包提供了以下 3 个类: AtomicBoolean:原子更新布尔类型。 AtomicInteger:原子更新整型。 AtomicLong

java并发变成及juc包的应用

╄→尐↘猪︶ㄣ 提交于 2020-01-28 03:51:22
多线程: windows操作系统是多任务操作系统,它以进程为单位,一个进程是一个包含有自身地址的程序,每个正在独立执行的程序都称为进程,进程是系统进行资源分配和调用的独立单位,每个进程有自己的内存空间和系统资源。系统可以分配给每个进程一段有限的使用CPU时间,CPU在这个时间片中执行某个进程,然后下一个时间片又跳到另一个进程中去执行,由于CPU转换较快,所以使的每个进程好像同时进行,多核CPU的多核同时运行,但是进程数远远大于核数,所以还是要依靠切换进程来做。一个线程则是进程中的执行流程,一个进程中可以同时包括多个线程,每个线程也可以得到一小段程序的执行时间,这样一个进程就可以具有多个并发执行的线程,在单线程中,程序的代码按照调用顺序依次往下执行,如果需要一个进程同时完成多段代码的操作,就需要产生多线程(多条执行路径)。多线程可以提高应用程序的使用率,为了有更高的几率抢到CPU的执行权,但我们不能保证哪一个线程能够在哪一个时刻抢到,所以线程的执行有随机性。在并发编程中,我们通常会遇到以下三个问题:原子性问题,可见性问题,有序性问题。 线程的两种调度模型:平均分配每个线程占用CPU的时间片,上面说的就是这种,第二种就是抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,会随机选一个,优先级高仅仅表示线程获取的cpu时间片的几率相对对多些

理解什么是线程安全性、原子性

只愿长相守 提交于 2020-01-24 08:47:08
目录 •写在前面 •原子性 加锁机制 •写在前面 进程想要执行任务需要依赖线程,换句话说就是进程中的最小执行单位就是线程,并且一个进程中至少有一个线程。提到多线程这里要说两个概念,就是串行和并行,搞清楚这个我们才能更好的理解多线程。所谓串行其实是相对于单条线程来执行多个任务来说的,我们就拿下载文件来举个例子,我们下载多个文件,在串行中它是按照一定的顺序去进行下载的,也就是说必须等下载完A之后,才能开始下载B,它们在时间上是不可能发生重叠的。 要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的和可变的状态的访问。要是的对象是线程安全的,需要采用同步机制来协同对对象可变状态的访问,如果无法实现协同,那么可能会导致数据破坏以及其他不该出现的结果。java中的同步机制是关键字synchronized,它提供了独占式的加锁方式,不仅如此还包括volatile类型变量,显式锁Lock以及原子变量。 单线程近似定义为“所见即所知”,那么定义线程安全性,则当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。一个类在单线程中运行都不正确,那么它肯定是不会是线程安全的。如果正确的实现了某个对象,那么在任何操作中(包括调用对象的公有方法或者对其公有域进行读写操作)都不会违背不变性条件或后验条件

C++ 原子操作和内存模型

故事扮演 提交于 2020-01-24 04:34:02
最近有一个困扰我的问题:如何使 C++ 的原子变量高效而且可移植? 我知道 Java volatile 是怎么工作的——它强制实行顺序一致性( sequential consistency ),但是这个方法并不总是效率最高的。 C++0x 原子变量在默认模式下也一样强制实施顺序一致性。如果没有特别的顺序注记( annotation ),它们和 Java volatile 几乎一模一样(有趣的是, Java 的 volatile 并不强制原子性——尽管有个 atomic library 来实现这一点)。 但是 C++ 可以在不同程度上放松顺序一致性的限制,如果使用得当的话,将会产生效率更高的代码。 在学习了一些 x86 的内存模型的知识后,我认识到一些基本的 lock-free pattern 无锁编程模式(比如我在 double-checked locking 重复检查锁模式中就发现了一种)可以直接运行而无需任何栅障同步( fence )。我们需要一种 C++ 编程思路,当编译成 x86 代码时,不产生栅障,而在编译成 alpha 或 Power PC 这样的非 x86 代码时,产生需要的栅障。 让事情更加有趣的是,一些其他的算法,如 Peterson 锁,在 x86 上还是需要内存栅障(请看我之前的 blog )。所以也不是简单的取消所有栅障就能搞定的。 我将我的问题缩短成

内存模型

你说的曾经没有我的故事 提交于 2020-01-24 03:52:45
在 C++11 标准中,一个重大的更新就是引入了 C++ 多线程内存模型。本文的主要目的在于介绍 C++ 多线程内存模型涉及到的一些原理和概念,以帮助大家理解 C++ 多线程内存模型的作用和意义。 1. 顺序一致性模型 (Sequential Consistency) 在介绍 C++ 多线程模型之前,让我们先介绍一下最基本的顺序一致性模型。对多线程程序来说,最直观,最容易被理解的执行方式就是顺序一致性模型。顺序一致性的提出者 Lamport 给出的定义是: “… the result of any execution is the same as if the operations of all the processors were executed in some sequential order, and the operations of each individual processor appear in this sequence in the order specified by its program.” 从这个定义中我们可以看出,顺序一致性主要约定了两件事情: (1). 从单个线程的角度来看,每个线程内部的指令都是按照程序规定的顺序 (program order) 来执行的 ; (2). 从整个多线程程序的角度来看

5.1 CUDA atomic原子操作

只谈情不闲聊 提交于 2020-01-24 03:45:55
和许多多线程并行问题一样,CUDA也存在互斥访问的问题,即当一个线程改变变量X,而另外一个线程在读取变量X的值,执行原子操作类似于有一个自旋锁,只有等X的变量在改变完成之后,才能执行读操作,这样可以保证每一次读取的都是最新的值. 在kernel 程序中,做统计累加,都需要使用原子操作:atomicAdd(); 原子操作很明显的会影响程序性能,所以可以的话,尽可能避免原子操作. CUDA原子操作API: C.1.1 atomicAdd() int atomicAdd(int* address, int val); unsigned int atomicAdd(unsigned int* address, unsigned int val); unsigned long long int atomicAdd(unsigned long long int* address, unsigned long long int val); 读取位于全局或共享存储器中地址address 处的32 位或64 位字old,计算(old + val),并将结果存储在存储器的同一地址中。这三项操作在一次原子事务中执行。该函数将返回old。 只有全局存储器支持64 位字。 C.1.2 atomicSub() int atomicSub(int* address, int val); unsigned int

x86_64处理器的指针赋值是原子操作吗?

…衆ロ難τιáo~ 提交于 2020-01-23 01:05:11
如题, x86_64处理器的指针赋值是原子操作吗? 说实话我很讨厌参与讨论那些似乎不确定东西,倒不是说我对未知不敬畏,而是参与讨论的人大多数都是似懂非懂,对,我说的不确定性指的是参与讨论的人的认知的不确定,如果你自己都似懂非懂,那么我说什么你都可以反驳我,说些 “貌似,可能,并不绝对” 的词汇来让事情变得混乱。 最近写了一篇文章: https://blog.csdn.net/dog250/article/details/103911008 里面提到了一句: 然后有人提出了质疑,其实我这句话后面还有个引用呢: 后面还夹杂了我的评价。 所以说,我的意思是, 以Intel的手册为准。 我觉得我应该收回上面的那句 “which is a pointer assignment operation, on the x86_64 platform which is an atomic operation.” 然后重新说出个所以然来。 那么,我们就看看Intel的手册怎么说: https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.pdf 有了这段 权威描述 ,本文似乎该结束了。 但是…

C# 原子操作 Interlocked

喜夏-厌秋 提交于 2020-01-20 21:53:16
前言 焦虑与恐惧,往往是是因为想要的太多,但行动却太少。将目标放低,制定足以达到目标的计划,并付之于一步一个脚印的行动。当你确信你在前进的时候,自然就不会焦虑;当你的行动为你积累了足够多的正向改变的时候,自然就不会恐惧;当量变中迸发出那么一星星的质变时,你将变的自信。 足够强大,你才会自信。 自信来源于强大的内心,强大的自己 。 开始 Interlocked 提供了方法来实现原子操作,对于多线程共享的变量来说,原子操作保证了线程安全,保证了变量值的正确性。 让我们看一个简单的例子,在下面例子中,我们 new 了 10 个 线程,并启动他们;他们各自循环10次调用 UseSharedValue 方法;在 UseSharedValue 方法中, 我们执行了 threadSharedValue++ 的操作。由于 threadSharedValue 的初始值为0,所以当程序跑完后,我们对于 threadSharedValue 的期望值为100。 using System; using System.Threading; namespace InterlockedExchange_Example { class MyInterlockedExchangeExampleClass { private static int threadSharedValue = 0; //每个线程内,循环10次

Redis分布式锁的实现

Deadly 提交于 2020-01-20 19:04:22
Redis分布式锁的实现 来自 https://www.cnblogs.com/Eugene-Jin/p/10801260.html 1.概述 分布式锁一般有三种实现方式:1.基于数据库实现分布式锁;2. 基于缓存(Redis,memcached,tair)实现分布式锁; 3.基于Zookeeper实现分布式锁。本片博客将介绍基于缓存实现分布式锁,这里主讲分别针对Redis 2.6.12 之前版本和Redis 2.6.12 及之后版本分布式锁的实现。 2.基于Redis(Redis 2.6.12版本之前)分布式锁的实现方式 (1)命令介绍   1)SETX    SETNX key value: setnx是『set if not exists』(即当key不存在时,则set)的简写。setnx具有原子性,当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0.   2)GETSET   GETSET key value: 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。当 key 存在但不是字符串类型时,返回一个错误。当 key 没有旧值时,也即是, key 不存在时,返回 nil 。   3)GET   GET key: 返回 key 所关联的字符串值;如果 key 不存在那么返回特殊值 nil