0
点赞
收藏
分享

微信扫一扫

element-ui 中 upload组件 如何传递额外的参数 ?

A邱凌 03-13 18:00 阅读 2

一、基本概述

1.1 引入背景

例:i++。假设由线程A和B需要对i进行加1的操作。线程A和线程B会分别从主内存中读取i值到自己的工作内存中。原本相加之后的值为3,但线程A和线程B分别加1后将值刷新到主内存,发现主内存的值为2,出现错误。

1.2 解决方法

保证线程A改写共享变量的操作是原子性(不能被中断的一个或一系列操作)的。采用CAS失败重试机制。

1.3 CAS(V,E,N)

1. V代表需要读写的内存位置(工作内存)
2. E代表进行比较的预期原值(主内存)
3. N代表打算写入的新值

具体流程:
假设线程A和B读取的i为2,那么线程A使用CAS操作时,会从工作内存中取出i值2与主内存中的值进行比较,发现与主内存中的值是相同的,则执行更新操作,并把值刷新到主内存中,主内存中的i值为3。线程B需要执行i加1的操作,发现工作内存中的i值2与主内存中的i值3是不一样,更新失败。然后会重新从主内存中取值到工作内存,再执行更新操作,直到成功。
由于每次都需要和主存中的最新值进行比较,比较需要结合volatile一起使用

1.4 特点

结合CAS和volatile可以实现无锁并发,适用于线程数较少,且多核CPU的场景下。

  • CAS是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃亏点再重试呗。
  • synchronized是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。

CAS体现的是无锁并发、无阻塞并发:

  1. 由于没有使用synchronized,线程不会阻塞;
  2. 如果竞争激烈,重试必然频繁发生,会影响效率。

二、底层原理

2.1 具体实现

底层使用的是Unsafe类。Unsafe对象提供了操作内存、线程的的方法,Unsafe不能直接被调用,只能通过反射调用

Unsafe只提供了3CAS方法:compareAndSwapObject、compareAndSwapInt、compareAndSwapLong. 

AtomicBoolean流程:

  1. 先把Boolean转换成整形;
  2. 使用compareAndSwapInt进行CAS。

源码如下,则char、float和double变量也适用类似的思路来实现:

public final boolean compareAndSet(boolean expect, boolean update) { 
    int e = expect ? 1 : 0; int u = update ? 1 : 0; 
    return unsafe.compareAndSwapInt(this, valueOffset, e, u); 
} 
AtomicInteger atomicInteger = new AtomicInteger(2020); 
System.out.println(atomicInteger.compareAndSet(2020,2021)); 

2.2 实现类为AtomicInteger

public class AtomicInteger extends Number implements java.io.Serializable
// 表示变量value在AtomicInteger实例对象内的内存偏移量
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; 
static { 
    try { 
        valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); 
    } catch (Exception ex) { 
        throw new Error(ex); 
    } 
} private volatile int value; 

在这里插入图片描述
在这里插入图片描述

2.3 存在的问题

  1. 循环开销大:如果线程自旋CAS长时间不成功,会给CPU带来非常大的执行开销
  2. 一次性只能保证一个共享变量的原子性,无法保证操作多个共享变量时的原子性。
解决方法:
1. 加锁;
2. 把多个共享变量合并成一个共享变量来操作,Java提供了AtomicReference类来保证引用对象之间的原子性,即多个共享变量放在一个对象里来操作。
  1. ABA问题
    ● 如果一个值原来是A,变成了B,最后又变成了A,那么使用CAS检查时发现它的值没有变化,但实际上却变化了。
    解决方法: 使用版本号,在变量前面加上版本号。使用Java提供的AtomicStampedReference来解决ABA问题。具体过程:1.先检查当前引用是否为预期引用;2.并且检查当前标志是否为预期标志(双重检查)
举报

相关推荐

0 条评论