原子操作

MongoDB CRUD的概念

给你一囗甜甜゛ 提交于 2020-02-04 16:53:10
一、原子性和事务 1.原子性 在MongoDB中,写操作是单个文档级别上的原子操作,即使该操作修改了单个文档中的多个嵌入文档。 2.多文档事务 当单个写操作(例如db.collection.updateMany())修改多个文档时,对每个文档的修改是原子性的,但整个操作不是原子性的。 在执行多文档写操作时,无论是通过单个写操作还是多个写操作,其他操作可能会交错进行。 对于需要对多个文档进行原子性读写的情况(在单个或多个集合中),MongoDB支持多文档事务: 在4.0版本中,MongoDB支持副本集上的多文档事务。 在版本4.2中,MongoDB引入了分布式事务,它在sharded集群上添加了对多文档事务的支持,并合并了对副本集上多文档事务的现有支持。 有关MongoDB事务的详细信息,请参阅事务页面。 重要: 在大多数情况下,与单个文档写入相比,多文档事务会带来更大的性能成本,而且多文档事务的可用性不应该代替有效的模式设计。对于许多场景,非规范化数据模型(嵌入文档和数组)对于您的数据和用例仍然是最优的。也就是说,对于许多场景,适当地对数据建模将最小化对多文档事务的需求。 有关其他事务使用注意事项(如运行时限制和oplog大小限制),请参见生产注意事项。 3. 并发控制 并发控制允许多个应用程序并发运行,而不会导致数据不一致或冲突。 一种方法是在只能具有唯一值的字段上创建惟一的索引

volatile修饰符

半世苍凉 提交于 2020-02-04 12:37:10
什么是volatile? 一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:   1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。   2)禁止进行指令重排序。 volatile 是一个类型修饰符。volatile 的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略。 volatile 的特性 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(实现可见性) 禁止进行指令重排序。(实现有序性) volatile 只能保证对单次读/写的原子性。i++ 这种操作不能保证原子性。 volatile 保证多线程的可见性,首要要明白内存模型的相关概念: 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入。由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执行速度很快,而从内存读取数据和向内存写入数据的过程跟CPU执行指令的速度比起来要慢的多,因此如果任何时候对数据的操作都要通过和内存的交互来进行,会大大降低指令执行的速度。因此在CPU里面就有了高速缓存。   也就是,当程序在运行过程中

Java中12个原子操作类

旧城冷巷雨未停 提交于 2020-02-04 02:55:22
Java 从 JDK 1.5 开始提供了 java.util.concurrent.atomic 包(以下简称Atomic包),这个包中的 原子操作类 提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。 因为变量的类型有很多种,所以在 Atomic 包里一共提供了 12个 类,属于以下 4 种类型的原子更新方式: 原子更新基本类型。 AtomicBoolean:原子更新布尔类型。 AtomicInteger:原子更新整型。 AtomicLong:原子更新长整型。 原子更新数组。 AtomicIntegerArray:原子更新整型数组里的元素。 AtomicLongArray:原子更新长整型数组里的元素。 AtomicReferenceArray:原子更新引用类型数组里的元素。 原子更新引用。 AtomicReference:原子更新对象引用。 AtomicMarkableReference:原子更新带有标记位的对象引用。 AtomicStampedReference:原子更新带有版本号的对象引用。 原子更新属性(字段)。 AtomicIntegerFieldUpdater:原子更新volatile修饰的整型的字段的更新器。 AtomicLongFieldUpdater:原子更新volatile修饰的长整型字段的更新器。

java并发编程之五、工具类

断了今生、忘了曾经 提交于 2020-02-01 23:58:06
java在线程同步和互斥方面在语言和工具方面都提供了相应的支撑,与此同时,java还提供了一系列的并发容器和原子类,来使得并发编程更容易。 一。并发容器 (一)。同步容器 同步容器指的是容器本身使用synchronized关键字来同步访问,包括我们都知道的HashTable,也包括Vector和Stack。另外,也可以通过工具类Collections. synchronizedList ( List <T> list)这个方法将线程不安全的ArrayList转成线程安全的包装类,其他的set,map等等,都有类似的包装类。 通常都任务同步容器的性能较差,但不足以导致问题,会导致问题的是对同步容易的迭代遍历。在迭代遍历的时候,依然需要对同步容器本身进行加锁才能保证线程安全。 1 List list = Collections.synchronizedList(new ArrayList()); 2 synchronized (list) { 3 Iterator i = list.iterator(); 4 while (i.hasNext()) 5 foo(i.next()); 6 } (二)。并发容器 同步容器的线程安全的保证主要是通过对所有的访问路径添加synchronized保护,往往造成性能不佳,所以在java 1.5之后,提供了更多的性能比较优秀的容器,这里称之为并发容器

并发编程(3)--原子操作CAS

和自甴很熟 提交于 2020-02-01 12:50:20
3 、原子操作 CAS Atom (不可分割) 什么是原子操作?如何实现原子操作? syn 基于阻塞的锁的机制, 1 、被阻塞的线程优先级很高, 2 、拿到锁的线程一直不释放锁怎么办? 3 、大量的竞争,消耗 cpu ,同时带来死锁或者其他安全。 CAS 的原理 CAS(Compare And Swap) ,指令级别保证这是一个原子操作。利用现代处理器都支持的CAS指令,循环这个指令直到成功为止。 三个运算符: 一个内存地址 V ,一个期望的值 A ,一个新值 B 基本思路:如果地址 V 上的值和期望的值 A 相等,就给地址 V 赋给新值 B ,如果不是,不做任何操作。 循环(死循环,自旋)里不断的进行 CAS 操作 CAS 的问题 1.ABA问题,可以用版本号来解决 A--- 》 B---- 》 A ,版本号 : A1 àB2-àA3 2.开销问题 CAS 操作长期不成功, cpu 不断的循环, 3.只能保证一个共享变量的原子操作 因为一个内存地址只会指向一个变量,可以使用下面的 AtomicReference Jdk 中相关原子操作类的使用 对于不太适合使用synchronize关键字的时候 ,比如简单的数字相加操作,用锁不方便,笨重的时候 Jdk中相关原子操作类的使用 更新基本类型类:AtomicBoolean,AtomicInteger,AtomicLong 更新数组类

Java并发67问

守給你的承諾、 提交于 2020-01-31 04:00:54
1. 并发和并行 2. 进程和线程 对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。 而在多个进程之间切换的时候,需要进行上下文切换。但是上下文切换势必会耗费一些资源。于是人们考虑,能不能在一个进程中增加一些“子任务”,这样减少上下文切换的成本。比如我们使用Word的时候,它可以同时进行打字、拼写检查、字数统计等,这些子任务之间共用同一个进程资源,但是他们之间的切换不需要进行上下文切换。 在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程。 随着时间的慢慢发展,人们进一步的切分了进程和线程之间的职责。 把进程当做资源分配的基本单元,把线程当做执行的基本单元,同一个进程的多个线程之间共享资源 3. 类变量,成员变量和局部变量 Java中共有三种变量,分别是类变量、成员变量和局部变量。他们分别存放在JVM的方法区、堆内存和栈内存中 public class Variables { /** * 类变量 */ private static int a ; /** * 成员变量 */ private int b ; /** * 局部变量 * @param c */ public

JUC中的原子操作类及其原理

百般思念 提交于 2020-01-31 03:46:37
  昨天简单的看了看Unsafe的使用,今天我们 看看 JUC中的原子类是怎么使用Unsafe的,以及分析一下其中的原理! 一.简单使用AtomicLong   还记的上一篇博客中我们使用了volatile关键字修饰了一个int类型的变量,然后两个线程,分别对这个变量进行10000次+1操作,最后结果不是20000,现在我们改成AtomicLong之后,你会发现结果始终都是20000了!有兴趣的可以试试,代码如下 package com.example.demo.study; import java .util.concurrent.atomic.AtomicLong; public class Study0127 { // 这是一个全局变量,注意,这里使用了一个原子类AtomicLong public AtomicLong num = new AtomicLong(); // 每次调用这个方法,都会对全局变量加一操作,执行10000次 public void sum() { for ( int i = 0; i < 10000; i++ ) { // 使用了原子类的incrementAndGet方法,其实就是把num++封装成原子操作 num.incrementAndGet(); System.out.println( "当前num的值为num= "+ num); } }

01-022【jvm】CAS与原子类ABA问题

旧城冷巷雨未停 提交于 2020-01-30 17:19:55
CAS即Compare and Swap ,体现了乐观锁思想 CAS CAS是什么? CAS:即Compare-And-Swap,它是一条CPU并发原语,它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。 获取共享变量时,为了保证该变量的可见性,需要使用volatile修饰。结合CAS和volatile可以实现无锁并发,适用于竞争不激烈、多核CPU的场景下。 底层原理 CAS并发原语 体现在java语言中就是sun.misc. UnSafe类 中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现CAS汇编指令。这是一种 完全依赖于硬件 的功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且 原语的执行必须是连续的,在执行过程中不允许被中断 ,也就是说 CAS是一条CPU的原子指令,不会造成所谓的数据不一致的问题 。 以AtomicInteger为例,源码 源码 public final int getAndIncrement ( ) { return unsafe . getAndAddInt ( this , valueOffset , 1 ) ; } 那么UnSafe类是什么? 在rt.jar中,jdk的基础类,其中方法均由native修饰

走进原子性

二次信任 提交于 2020-01-29 13:48:27
走进原子性 问题:线程之间的协作 标准解决方法:上锁 实现一个计数器和互斥锁 locking的问题 硬件同步的早期 Compare and Swap(CAS) 用CAS来实现计数器 lock-free和wait-free算法 原子变量类 细颗粒度意味着轻量级 十五年前,多核处理器是特别的系统,需要花费成百上千的美元。今天,多核处理器系统又便宜又丰富,几乎每一个主要的微处理器都对并发有内部支持。 为了利用好多核的优势,软件也架构在多线程上。但是,仅仅将一个工作简单地划分为几个线程并不能发挥出硬件的优势-----你必须要确保你的线程大部分时间是在工作,而不是在等待工作,或者是在共享数据结构上等锁。 问题:线程之间的协作 几乎没有task能够真正地并发运行,不需要线程之间的协作。想象一个线程池,那里tasks是互相独立地运行的。假如一个线程池要为一个queue工作,那么为queue加入或者删除元素都必须是线程安全的,那意味着在head,tail,或者内部node的引用之间的协作。正是这样的协作导致了所有的问题。 标准解决方法:上锁 对于共享字段的协作获取的传统做法是通过synchronize,它确保所有对共享字段的获取都是拿着锁的状态。使用synchronize,你可以确保不管哪个保护着一些变量的线程取得锁,它都会对这些变量有着独享,而对这些变量的改变又会变成可见的

Java内存模型与线程

假如想象 提交于 2020-01-29 07:32:02
Java内存模型与线程 每秒事务处理数(Transactions Per Second,TPS)、 Java语言和虚拟机提供了许多工具,把并发编程的门槛降低了不少。另外,各种中间件服务器、各类框架 12.2 硬件的效率与一致性 现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存(Cache)来作为内存与处理器之间的缓冲: 为了解决一致性的问题,需要各个处理器访问缓存时都遵循一些协议,在读写时要根据协议来进行操作,这类协议有MSI、MESI(IllinoisProtocol)、MOSI、Synapse、Firefly及Dragon Protocol,等等 为了使得处理器内部的运算单元能尽量被充分利用,处理器可能会对输入代码进行乱序执行(Out-Of-Order Execution)优化,处理器会在计算之后将乱序执行的结果重组,保证该结果与顺序执行的结果是一致的,类似,Java虚拟机的即时编译器中也有类似的指令重排序(Instruction Reorder)优化。 12.3 Java内存模型 用来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果。 12.3.1 主内存与工作内存 此处的变量包括了实例字段、静态字段和构成数组对象的元素,但是不包括局部变量与方法参数,因为后者是线程私有的[插图],不会被共享