原子操作

redis处理库存问题

谁都会走 提交于 2019-11-27 14:20:11
12月份重构公司社群活动产品,原来自己不是很成熟,按传统的形式处理卖票的信息-现在回首很多地方都会出问题。 先说下背景:业务是卖票!所以自然而然会遇到高并发下的库存问题 搜了很多网上提供以下几种方案: 1.并发数很小,不考虑并发的话采用Redis的原子操作。缺点也很显然,高并发肯定是有问题的!对应方案如下 http://blog.csdn.net/wujiangwei567/article/details/51210600 2.高并发请求采用队列形式,化解为单线程。消费时再使用Redis原子操作加减库存 3.采用Redis的分布式锁 现在采用的第三种方式 来源: CSDN 作者: 天降爆米花 链接: https://blog.csdn.net/dream20nn/article/details/53490147

并发问题的源头—原子性、可见性、有序性。

女生的网名这么多〃 提交于 2019-11-27 13:04:37
源头的源头——为什么会有这三个问题。 先说并发问题的源头: 原子性问题是因为多线程切换,导致程序没有按照自己的意愿正确执行。 可见性问题是因为数据在缓存中的更新不能及时的通知其它线程。 有序性问题是因为编译器优化使程序的执行顺序发生变化导致程序发生异常结果。 那么,这三个问题的源头又是什么呢?——那就是 为了缓解CPU、内存、硬盘这三者的速度差异带来的问题 。 我们都知道,这三者的速度差异非常的大,无论哪一代计算机都有这样的特征。由于木桶效应,所以就需要有一些方法优化它们速度差异所带来的性能瓶颈,这里我们说跟并发问题有关的: CPU增加缓存,避免每次都在内存读取数据。 操作系统层面增加进程、线程的概念,每个程序分时复用CPU,缓解CPU与磁盘I/O的速度差异。 编译器优化执行指令,使CPU更好利用缓存。 缓存的可见性问题 在现代多核CPU中,每个核心都会有自己的独立缓存。而CPU利用缓存,缓和了CPU与内存之间的速度差异带来的问题。但是,我们都知道一个运行时的程序,它的运行数据是放在内存当中的。而CPU在计算数据的数值后,把存放在缓存中的值再次写回内存的时机是不确定的。这样,就会发生缓存可见性问题。当然,其实还有很多地方都有缓存可见性问题,这里只说了其中一个。 例如:当CPU的多个核心参与一个程序的运行,当不同核心间进行了各自的计算,把计算后的值放入自己的缓存而不选择写入内存中

volatile 关键字 和 i++ 原子性

浪尽此生 提交于 2019-11-26 23:56:45
1 package com.mozq.multithread; 2 3 /** 4 * 深入理解Java虚拟机 volatile 关键字 和 i++ 原子性。 5 */ 6 public class VolatileTest { 7 public static volatile int race = 0; 8 9 private static final int THREADS_COUNT = 20; 10 11 public static void main(String[] args) { 12 Thread[] threads = new Thread[THREADS_COUNT]; 13 for(int i = 0; i < THREADS_COUNT; i++){ 14 threads[i] = new Thread(()-> {//自增 10000 次 15 for (int j = 0; j < 10000; j++) { 16 race++; 17 } 18 }); 19 threads[i].start(); 20 } 21 //等待所有线程执行完毕 22 for(int i = 0; i < THREADS_COUNT; i++){ 23 try { 24 threads[i].join(); 25 } catch (InterruptedException e

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

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

volatile的工作原理

邮差的信 提交于 2019-11-26 20:59:19
volatile的特性: volatile可见性:对一个volatile的读,总可以看到对这个变量最终的写; volatile原子性:volatile对单个读/写具有原子性(32位Long、Double),但是复合操作除外,例如:i++; jvm底层采用“内存屏障”来实现volatile语义。 volatile的内存语义及实现:   在JMM中,线程之间的通信采用共享内存来实现的。 volatile内存语义是: 当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值立即刷新到主内存中; 当读一个volatile变量时,JMM会把该线程对应的本地内存设置为无效,直接从主内存中读取共享变量。 volatile的底层实现是通过插入内存屏障,但是对于编译器来说,发现一个最优布置来最小化插入内存屏障的总数几乎是不可能的,所以,JMM采用保守策略。如下: 在每一个volatile写操作前面插入一个StoreStore屏障 在每一个volatile写操作后面插入一个StoreLoad屏障 在每一个volatile读操作后面插入一个LoadLoad屏障 在每一个volatile读操作后面插入一个LoadStore屏障 StoreStore屏障可以保证在volatile写之前,其前面的所有普通写操作都已经刷新到主内存中;

JUC之原子类

时光总嘲笑我的痴心妄想 提交于 2019-11-26 10:20:57
JUC原子类 文章目录 JUC原子类 一、分类 二、基本类型 1、AtomicInteger 2、AtomicLong 3、AtomicBoolean 三、数组类型 1、AtomicIntegerArray 四、引用类型 1、AtomicReference 2、AtomicReferenceArray 五、对象属性类型 1、AtomicIntegerFieldUpdater(抽象类) demo 一、分类 Juc原子类可以分为以下四大类: 基本类型 AtomicInteger, AtomicLong, AtomicBoolean 数组类型 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray 引用类型 AtomicReference, AtomicStampedRerence, AtomicMarkableReference 对象属性类型 AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater 二、基本类型 1、AtomicInteger public class AtomicInteger extends Number implements java . io . Serializable { private

Java并发之volatile关键字

冷暖自知 提交于 2019-11-26 01:08:18
引言 说到多线程,我觉得我们最重要的是要理解一个临界区概念。 举个例子,一个班上1个女孩子(临界区),49个男孩子(线程),男孩子的目标就是这一个女孩子,就是会有竞争关系(线程安全问题)。推广到实际场景,例如对一个数相加或者相减等等情形,因为操作对象就只有一个,在多线程环境下,就会产生线程安全问题。理解临界区概念,我们对多线程问题可以有一个好意识。 Jav内存模型(JMM) 谈到多线程就应该了解一下Java内存模型(JMM)的抽象示意图.下图: 线程A和线程B执行的是时候,会去读取共享变量(临界区),然后各自拷贝一份回到自己的本地内存,执行后续操作。 JMM模型是一种规范,就像Java的接口一样。JMM会涉及到三个问题:原子性,可见性,有序性。 所谓原子性。就是说一个线程的执行会不会被其他线程影响的。他是不可中断的。举个例子: int i=1 这个语句在Jmm中就是原子性的。无论是一个线程执行还是多个线程执行这个语句,读出来的i就是等于1。那什么是非原子性呢,按道理如果Java的代码都是原子性,应该就不会有线程问题了啊。其实JMM这是规定某些语句是原子性罢了。举个非原子性例子: i ++; 这个操作就不是原子性的了。因为他就是包含了三个操作:第一读取i的值,第二将i加上1,第三将结果赋值回来给i,更新i的值。 所谓可见性。可见性表示如果一个值在线程A修改了

分布式事务(一)理论篇

我的未来我决定 提交于 2019-11-25 21:39:57
摘要说明: 简单的说 事务 的本质就是将多个非原子性的操作构造成一个“原子性”的执行单元的机制;即多个原子操作要么全部成功,要么全部失败即 回滚 ; 但往往一个业务会因为多种原因需要划分成多个这样的节点,通常的原因有 业务划分产生多个节点如微服务; 由于多个数据源产生多个节点; 简单的说分布式事务需要保证这些小节点要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库或操作的数据一致性。 一、什么是分布式事务? 事务 提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整个事务的回滚。简单地说,事务提供一种“要么什么都不做,要么做全套(All or Nothing)”机制。 那什么是 分布式事务 ? 举个例子,微服务中有两个服务分别是服务A和服务B,若服务A的一个接口a调用服务B的接口B成功后处理自己的逻辑时出现异常,那么服务A回滚本身接口a的业务的同时,如何协调服务B将其接口b的业务回滚;这就是 分布式事务 ; 分布式事务 就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用