当一个处理器想要更新某个变量的值时,向总线发出LOCK#信号,此时其他处理器的对该变量的操作请求将被阻塞,发出锁定信号的处理器将独占共享内存,于是更新就是原子性的了。

1、compareAndSet----比较并交换

AtomicInteger.conpareAndSet(int expect, indt update)

    public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

第一个参数为拿到的期望值,如果期望值没有一致,进行update赋值,如果期望值不一致,证明数据被修改过,返回fasle,取消赋值

例子:

package com.jian8.juc.cas;

import java.util.concurrent.atomic.AtomicInteger;

/**
* 1.CAS是什么?
* 1.1比较并交换
*/
public class CASDemo {
public static void main(String[] args) {
checkCAS();
} public static void checkCAS(){
AtomicInteger atomicInteger = new AtomicInteger(5);
System.out.println(atomicInteger.compareAndSet(5, 2019) + "\t current data is " + atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(5, 2014) + "\t current data is " + atomicInteger.get());
}
}

输出结果为:

true	 current data is 2019
false current data is 2019

2、CAS底层原理?对Unsafe的理解

比较当前工作内存中的值和主内存中的值,如果相同则执行规定操作,否则继续比较知道主内存和工作内存中的值一直为止

  1. atomicInteger.getAndIncrement();

        public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
    }
  2. Unsafe

    • 是CAS核心类,由于Java方法无法直接访问地层系统,需要通过本地(native)方法来访问,Unsafe相当于一个后门,基于该类可以直接操作特定内存数据。Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,因为Java中CAS操作的执行依赖于Unsafe类的方法。

      Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都直接调用操作系统底层资源执行相应任务

    • 变量valueOffset,表示该变量值在内存中的偏移地址,因为Unsafe就是根据内存便宜地址获取数据的

    • 变量value用volatile修饰,保证多线程之间的可见性

  3. CAS是什么

    CAS全称呼Compare-And-Swap,它是一条CPU并发原语

    他的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。

    CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中各个方法。调用Unsafe类中的CAS方法,JVM会帮我们实现CAS汇编指令。这是一种完全依赖于硬件的功能,通过他实现了原子操作。由于CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成数据不一致问题。

    //unsafe.getAndAddInt
    public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
    var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
    return var5;
    }

    var1 AtomicInteger对象本身

    var2 该对象的引用地址

    var4 需要变动的数据

    var5 通过var1 var2找出的主内存中真实的值

    用该对象前的值与var5比较;

    如果相同,更新var5+var4并且返回true,

    如果不同,继续去之然后再比较,直到更新完成

3、CAS缺点

  1. ** 循环时间长,开销大**

    例如getAndAddInt方法执行,有个do while循环,如果CAS失败,一直会进行尝试,如果CAS长时间不成功,可能会给CPU带来很大的开销

  2. 只能保证一个共享变量的原子操作

    对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁来保证原子性

  3. ABA问题

三、原子类AtomicInteger的ABA问题?原子更新引用?

1、ABA如何产生

CAS算法实现一个重要前提需要去除内存中某个时刻的数据并在当下时刻比较并替换,那么在这个时间差类会导致数据的变化。

比如线程1从内存位置V取出A,线程2同时也从内存取出A,并且线程2进行一些操作将值改为B,然后线程2又将V位置数据改成A,这时候线程1进行CAS操作发现内存中的值依然时A,然后线程1操作成功。

==尽管线程1的CAS操作成功,但是不代表这个过程没有问题==

2、如何解决?原子引用

示例代码:

package juc.cas;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString; import java.util.concurrent.atomic.AtomicReference; public class AtomicRefrenceDemo {
public static void main(String[] args) {
User z3 = new User("张三", 22);
User l4 = new User("李四", 23);
AtomicReference<User> atomicReference = new AtomicReference<>();
atomicReference.set(z3);
System.out.println(atomicReference.compareAndSet(z3, l4) + "\t" + atomicReference.get().toString());
System.out.println(atomicReference.compareAndSet(z3, l4) + "\t" + atomicReference.get().toString());
}
} @Getter
@ToString
@AllArgsConstructor
class User {
String userName;
int age;
}

输出结果

true	User(userName=李四, age=23)
false User(userName=李四, age=23)

3、时间戳的原子引用

新增机制,修改版本号

package com.jian8.juc.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference; /**
* ABA问题解决
* AtomicStampedReference
*/
public class ABADemo {
static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1); public static void main(String[] args) {
System.out.println("=====以下时ABA问题的产生=====");
new Thread(() -> {
atomicReference.compareAndSet(100, 101);
atomicReference.compareAndSet(101, 100);
}, "Thread 1").start(); new Thread(() -> {
try {
//保证线程1完成一次ABA操作
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicReference.compareAndSet(100, 2019) + "\t" + atomicReference.get());
}, "Thread 2").start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("=====以下时ABA问题的解决====="); new Thread(() -> {
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName() + "\t第1次版本号" + stamp);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
System.out.println(Thread.currentThread().getName() + "\t第2次版本号" + atomicStampedReference.getStamp());
atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
System.out.println(Thread.currentThread().getName() + "\t第3次版本号" + atomicStampedReference.getStamp());
}, "Thread 3").start(); new Thread(() -> {
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName() + "\t第1次版本号" + stamp);
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean result = atomicStampedReference.compareAndSet(100, 2019, stamp, stamp + 1); System.out.println(Thread.currentThread().getName() + "\t修改是否成功" + result + "\t当前最新实际版本号:" + atomicStampedReference.getStamp());
System.out.println(Thread.currentThread().getName() + "\t当前最新实际值:" + atomicStampedReference.getReference());
}, "Thread 4").start();
}
}

输出结果:

=====以下时ABA问题的产生=====
true 2019
=====以下时ABA问题的解决=====
Thread 3 第1次版本号1
Thread 4 第1次版本号1
Thread 3 第2次版本号2
Thread 3 第3次版本号3
Thread 4 修改是否成功false 当前最新实际版本号:3
Thread 4 当前最新实际值:100

java:原子类的CAS的更多相关文章

  1. Java原子类中CAS的底层实现

    Java原子类中CAS的底层实现 从Java到c++到汇编, 深入讲解cas的底层原理. 介绍原理前, 先来一个Demo 以AtomicBoolean类为例.先来一个调用cas的demo. 主线程在f ...

  2. 对Java原子类AtomicInteger实现原理的一点总结

    java原子类不多,包路径位于:java.util.concurrent.atomic,大致有如下的类: java.util.concurrent.atomic.AtomicBoolean java. ...

  3. Java原子类AtomicInteger实现原理的一点总结

    java原子类不多,包路径位于:java.util.concurrent.atomic,大致有如下的类: java.util.concurrent.atomic.AtomicBoolean java. ...

  4. 死磕 java原子类之终结篇(面试题)

    概览 原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换. 原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割 ...

  5. 源码编译OpenJdk 8,Netbeans调试Java原子类在JVM中的实现(Ubuntu 16.04)

    一.前言 前一阵子比较好奇,想看到底层(虚拟机.汇编)怎么实现的java 并发那块. volatile是在汇编里加了lock前缀,因为volatile可以通过查看JIT编译器的汇编代码来看. 但是原子 ...

  6. JUC源码学习笔记4——原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法

    JUC源码学习笔记4--原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法 volatile的原理和内存屏障参考<Java并发编程的艺术> 原子类源码基于JDK8 ...

  7. Java 原子类 java.util.concurrent.atomic

    Java 原子类 java.util.concurrent.atomic 1.i++为什么是非线程安全的 i++其实是分为3个步骤:获取i的值, 把i+1, 把i+1的结果赋给i 如果多线程执行i++ ...

  8. CAS 算法与 Java 原子类

    乐观锁 一般而言,在并发情况下我们必须通过一定的手段来保证数据的准确性,如果没有做好并发控制,就可能导致脏读.幻读和不可重复度等一系列问题.乐观锁是人们为了应付并发问题而提出的一种思想,具体的实现则有 ...

  9. Java原子类实现原理分析

    在谈谈java中的volatile一文中,我们提到过并发包中的原子类可以解决类似num++这样的复合类操作的原子性问题,相比锁机制,使用原子类更精巧轻量,性能开销更小,本章就一起来分析下原子类的实现机 ...

随机推荐

  1. PyQt(Python+Qt)学习随笔:视图中的dragDropMode属性对dragEnabled和acceptDrops属性的影响

    老猿Python博文目录 老猿Python博客地址 在<PyQt(Python+Qt)学习随笔:QAbstractItemView的dragEnabled和dragDropMode属性的关系&g ...

  2. 分布式计算框架-Spark(spark环境搭建、生态环境、运行架构)

    Spark涉及的几个概念:RDD:Resilient Distributed Dataset(弹性分布数据集).DAG:Direct Acyclic Graph(有向无环图).SparkContext ...

  3. Java安全之Unsafe类

    Java安全之Unsafe类 0x00 前言 前面使用到的一些JNI编程和Javaagent等技术,其实在安全里面的运用非常的有趣和微妙,这个已经说过很多次.后面还会发现一些比较有意思的技术,比如AS ...

  4. 条件循环语句组成了Python代码的骨架

    条件控制 我们都知道流程图是有多个分支的,程序中也是如此,在Python中是用if语句来判断程序该走哪个分支的.它的执行过程如下: 代码执行过程如下: if if语句的一般形式如下: if condi ...

  5. UOJ80 二分图最大权匹配

    草,学了一下午假板子,sb博客害人 题目大意: 一个教室有\(n\)个男生和\(m\)个女生,某些男女之间愿意早恋(雾),其早恋好感度为\(w_i\),问怎样让男女配对使得班里好感度之和最大 \(n\ ...

  6. 【题解】折纸 origami [SCOI2007] [P4468] [Bzoj1074]

    [题解]折纸 origami [SCOI2007] [P4468] [Bzoj1074] 传送门:折纸 \(\text{origami [SCOI2007] [P4468]}\) \(\text{[B ...

  7. hiveSQL和MySQL区别

    1.hive支持按行分割,按字段分割,如按','分割: lateral view explode(split( , ',')) 2.hive不支持等值连接,即不支持where a.id = b.id的 ...

  8. Java经典小游戏——贪吃蛇简单实现(附源码)

    一.使用知识 Jframe GUI 双向链表 线程 二.使用工具 IntelliJ IDEA jdk 1.8 三.开发过程 3.1素材准备 首先在开发之前应该准备一些素材,已备用,我主要找了一个图片以 ...

  9. 【Scrapy笔记】使用方法

    安装: 1.pip install wheel 安装wheel 2.安装Twisted a.访问 http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted ...

  10. SMART

    SMART原则: S(Specific):目标必须是具体的,要对标特定的工作指标,不能笼统: M(Measurable):目标必须是可衡量的,衡量的指标是数量化或者行为化的,验证这些指标的数据或者信息 ...