原子操作

java.util.concurrent.atomic原子操作类包

杀马特。学长 韩版系。学妹 提交于 2019-11-29 06:42:26
这个包里面提供了一组原子变量类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。实际上是借助硬件的相关指令来实现的,不会阻塞线程(或者说只是在硬件级别上阻塞了)。可以对基本数据、数组中的基本数据、对类中的基本数据进行操作。原子变量类相当于一种泛化的volatile变量,能够支持原子的和有条件的读-改-写操作。 java.util.concurrent.atomic中的类可以分成4组: 标量类(Scalar):AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference 数组类:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray 更新器类:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater 复合变量类:AtomicMarkableReference,AtomicStampedReference 第一组AtomicBoolean,AtomicInteger

线程安全性问题

淺唱寂寞╮ 提交于 2019-11-28 23:15:06
什么是线程安全性 当多个线程访问某个类,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类为线程安全的。----《并发编程实战》。 什么是线程不安全 多线程并发访问时,得不到正确的结果。 结果: 产生线程不安全问题的原因: num++ 不是原子性操作,被拆分成好几个步骤,在多线程并发执行的情况下,因为cpu调度,多线程快递切换,有可能两个同一时刻都读取了同一个num值,之后对它进行+1操作,导致线程安全性。 原子性操作 什么是原子性操作 一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。通俗点讲:操作要成功一起成功、要失败大家一起失败。 如何把非原子性操作变成原子性 synchronize关键字,使得操作具有原子性 volatile关键字仅仅保证可见性,并不保证原子性 深入理解synchronized 内置锁:每个java对象都可以用做一个实现同步的锁,这些锁称为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。 互斥锁:内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞

并发编程-CAS

泄露秘密 提交于 2019-11-28 21:43:09
CAS (compareAndSwap),中文叫比较交换,一种 无锁原子算法 。 过程是这样:它包含 3 个参数 CAS(V,E,N),V表示要更新变量的值,E表示预期值,N表示新值。仅当 V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做两个更新,则当前线程则什么都不做。最后,CAS 返回当前V的真实值。CAS 操作时抱着乐观的态度进行的,它总是认为自己可以成功完成操作。 CAS是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,其实现方式是基于硬件平台的汇编指令,在intel的CPU中,使用的是cmpxchg指令,就是说 CAS是靠硬件实现的 ,从而在硬件层面提升效率。 当多个线程同时使用CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。 失败的线程不会挂起 ,仅是被告知失败,并且允许再次尝试,当然也允许实现的线程放弃操作。基于这样的原理,CAS 操作即使没有锁,也可以发现其他线程对当前线程的干扰。 与锁相比,使用CAS会使程序看起来更加复杂一些,但由于其非阻塞的,它对死锁问题天生免疫,并且,线程间的相互影响也非常小。更为重要的是,使用无锁的方式完全没有锁竞争带来的系统开销,也没有线程间频繁调度带来的开销,因此,他要比基于锁的方式拥有更优越的性能。 简单的说,CAS 需要你额外给出一个期望值

浅析Java内存模型

走远了吗. 提交于 2019-11-28 19:49:57
本篇文章基本上都是概念性的知识,理解记忆为主: 1、Java内存结构 java文件,首先要经过编程成为class文件,然后通过 类装载器加载到jvm 中去执行。这个jvm(蓝色线框起来的这部分)就是 java运行时数据区 ,意思就是java代码在运行的时候,这些数据要存放在不同的内存空间里面。jvm就是指代这个的。当然了上面的运行时数据区jvm是 jdk1.7 版本的。也就是说不同的jdk版本,这个jvm的构成是不一样的。如下是Java7的内存结构: 我们可以看到一共划分了5个部分,其中java堆区和方法区还是所有线程共享的区域。那么为什么要设置成线程共享的呢?因为假设一个数据,每个线程都保留一份,那其中有一个线程将这个数据更改了。其他的线程发现自己的数据没有变,这就出现了问题了。于是设计成了所有线程共享,java内存模型出来了。 2、JMM Java的内存模型也叫做JMM。但这个模型不是像内存结构一样,是真实存在的。java内存模型是一个抽象出来的概念。意思是把一部分内存区域设计成所有线程共享的,一个线程对数据更改,其他线程就能立刻知道。 Java内存结构和Java内存模型的区别 (1)java内存结构是解决java中的数据如何存放的问题。 (2)java内存模型是解决java中多个线程共享数据的问题。 Java内存模型的来源 阶段一 在计算机发展的第一个阶段

串烧 JavaCAS相关知识

旧巷老猫 提交于 2019-11-28 16:25:10
JMM与问题引入 为啥先说JMM,因为CAS的实现类中维护的变量都被volatile修饰, 这个volatile 是遵循JMM规范(不是百分百遵循,下文会说)实现的保证多线程并发访问某个变量实现线程安全的手段 一连串的知识点慢慢缕 首先说什么是JMM, JMM就是大家所说的java的内存模型, 它是人们在逻辑上做出的划分, 或者可以将JMM当成是一种规范, 有哪些规范呢? 如下 可见性: 某一个线程对内存中的变量做出改动后,要求其他的线程在第一事件内马上马得到通知,在CAS的实现中, 可见性其实是通过不断的while循环读取而得到的通知, 而不是被动的得到通知 原子性: 线程在执行某个操作的时,要么一起成功,要么就一起失败 有序性: 为了提高性能, 编译器处理器会进行指令的重排序, 源码-> 编译器优化重排 -> 处理器优化重排 -> 内存系统重排 -> 最终执行的命令 JVM运行的实体是线程, 每一个线程在创建之后JVM都会为其创建一个工作空间, 这个工作空间是每一个线程之间的私有空间, 并且任何两条线程之间的都不能直接访问到对方的工作空间, 线程之间的通信,必须通过共享空间来中转完成 JMM规定所有的变量全部存在主内存中,主内存是一块共享空间,那么如果某个线程相对主内存中共享变量做出修改怎么办呢? 像下面这样: 将共享变量的副本拷贝到工作空间中 对变量进行赋值修改

原子性、可见性、有序性与重排序

时光怂恿深爱的人放手 提交于 2019-11-28 15:40:09
1. 原子性(Atomicity): 一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。 我们先来看看哪些是原子操作,哪些不是原子操作,先有一个直观的印象: int k = 5; //代码1 k++; //代码2 int j = k; //代码3 k = k + 1; //代码4 上面这4个代码中只有代码1是原子操作。 代码2:包含了三个操作。1.读取变量k的值;2.将变量k的值加1;3.将计算后的值再赋值给变量k。 代码3:包含了两个操作。1.读取变量k的值;2.将变量k的值赋值给变量j。 代码4:包含了三个操作。1.读取变量k的值;2.将变量k的值加1;3.将计算后的值再赋值给变量k。 注:实际编译成字节码后,这些代码的字节码条数跟我上面的操作数可能有出入,但为了更容易理解,并且这些操作已经总体上能说明问题,因此使用这些操作来分析。 上面这个例子只是简单的分析了几种常见的情况。具体到底层的指令(上文内存间操作提到的8个指令),由Java内存模型来直接保证的原子性变量操作包括read、load、assign、use、store和write,我们大致可以认为基本数据类型的访问读写是具备原子性的。如果应用场景需要一个更大范围的原子性保证,Java内存模型还提供了lock和unlock操作来满足这种需求

并发编程-java内存模型

十年热恋 提交于 2019-11-28 13:44:14
1. 基本概念   程序:静态,用于完成某些功能的代码。   进程:动态,运行中的程序   线程:进程中的实际运作单位,一个进程可以包含一个或多个线程。 2. JVM内存区域 堆:线程共享,存放实例对象 (OOM) 虚拟机栈 :线程私有 ,Java方法在运行时的内存模型 (OOM),存放局部变量、引用类型数据的地址、操作数栈 本地方法栈 方法区 : 线程共享,存放类信息,常量,静态变量等 程序计数器 : 线程私有, 存放下一条指令的地址 3. java内存模型(java memory model, JMM,抽象的模型) 作用: 规范内存空间和工作空间数据的交互 主内存: 线程共享的信息 工作内存:线程私有的信息。基本数据类型,直接分配到工作内存。引用的地址存放在工作内存,引用的对象存放在堆中。 工作方式:   线程修改私有数据,直接在工作空间改   线程修改共享数据,把数据复制到工作空间中,在工作空间中修改,修改完成后,刷新到内存。 4. 硬件内存架构 CPU缓存一致性问题的解决方案: 1. 总线加锁 : 降低CPU的吞吐量 2. 缓存上的一致性协议 当CPU在CACHE中操作数据时,如果该数据是共享变量,数据在CACHE读到寄存器中,进行新修改,并更新内存数据 CaCHE LINE置无效,其他的CPU就从内存中读数据 5. java线程与硬件处理器 6. 并发编程的三个特性

volatile关键字浅析

风格不统一 提交于 2019-11-28 13:01:43
volatile关键字浅析 在并发编程中,volatile是很常用的一个修饰符。JDK官方文档是这么形容volatile的: The Java programming language provides a second mechanism, volatile fields, that is more convenient than locking for some purposes. A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable. 这里意思很明白,volatile在某些用途下比锁更方便,一个变量被声明为volatile,jvm能够保证所有的线程都看到的是一致的变量,也就说一个线程对一个共享变量修改,其他线程能够立即看到最新的值。 volatile在某些情况下可以代替锁,比synchronized成本和开销更低,因为不会引起线程的上下文切换,为什么上下文切换就会开销比较大,因为原来缓存的指令和数据都没用了,要重新加载指令和数据到缓存中,你说开销大不大。 1.首先看看可见性 volatile修饰的共享变量,当该变量发生写操作时,把该变量刷新到内存中

浅析Volatile关键字

跟風遠走 提交于 2019-11-28 12:56:48
浅析Volatile关键字 在java中线程并发中,线程之间通信方式分为两种:共享内存和消息传递。共享内存指的是多个线程之间共享内存的属性状态;消息传递指的是线程之间发送信息来通信。在介绍volatile,我们先了解一下共享内存一些基本概念。 JMM Java内存模型(简称JMM)控制线程通信,可以分为主内存和本地内存,每个线程拥有一个本地内存。 如图,一般主存只有一个,根据线程数不同,本地内存(又称工作内存)数目也不同,本地内存是抽象出来的概念,实际上不存在。 线程之间通过内存来同步状态可以分为以下几个步骤: 1、 线程1从主存获取变量x=1,假设此时其他线程x都为1 2、 线程1将本地内存中x值修改为2 3、 线程1将本地内存中x值放回主存 4、 其他线程同步主存数据 以上,就是理想状态线程之间通过主存通信状态,保证了内存的 可见性 。 指令重排序 java程序在运行时,并不会严格按照程序代码编写的顺序执行代码,会对其进行重排序。例如以下例子: 在程序执行代码的时候,步骤1和步骤2可能被重排序,导致2可能在1之前先执行,但是重排序的前提是 在单线程情况下不会改变运行结果, 因此1和2可以重排序,但是3引用了1和2中的变量,因此3不会被重排序到1或者2之前。在单线程情况下,重排序不会影响,但在多线程中会导致结果不可预见,可以使用其他方法来保证 有序性 。 原子性操作 前面提到了

重新学习MySQL数据库6:浅谈MySQL的中事务与锁

陌路散爱 提交于 2019-11-28 10:36:27
『浅入深出』MySQL 中事务的实现 在关系型数据库中,事务的重要性不言而喻,只要对数据库稍有了解的人都知道事务具有 ACID 四个基本属性,而我们不知道的可能就是数据库是如何实现这四个属性的;在这篇文章中,我们将对事务的实现进行分析,尝试理解数据库是如何实现事务的,当然我们也会在文章中简单对 MySQL 中对 ACID 的实现进行简单的介绍。 事务其实就是并发控制的基本单位;相信我们都知道,事务是一个序列操作,其中的操作要么都执行,要么都不执行,它是一个不可分割的工作单位;数据库事务的 ACID 四大特性是事务的基础,了解了 ACID 是如何实现的,我们也就清除了事务的实现,接下来我们将依次介绍数据库是如何实现这四个特性的。 原子性 在学习事务时,经常有人会告诉你,事务就是一系列的操作,要么全部都执行,要都不执行,这其实就是对事务原子性的刻画;虽然事务具有原子性,但是原子性并不是只与事务有关系,它的身影在很多地方都会出现。 由于操作并不具有原子性,并且可以再分为多个操作,当这些操作出现错误或抛出异常时,整个操作就可能不会继续执行下去,而已经进行的操作造成的副作用就可能造成数据更新的丢失或者错误。 事务其实和一个操作没有什么太大的区别,它是一系列的数据库操作(可以理解为 SQL)的集合,如果事务不具备原子性,那么就没办法保证同一个事务中的所有操作都被执行或者未被执行了