深入理解CAS

什么是CAS

为什么要学CAS:大厂你必须深入研究底层!有所突破!

java层面的cas------->compareAndSet

compareAndSet(int expectedValue, int newValue) 期望并更新,达到期望值就更新、否则就不更新!

package org.example.cas;

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
//JAVA CAS -> 比较并交换
//期望、更新
//compareAndSet(int expectedValue, int newValue)
//如果我期望的值达到了那么就跟新、否则就不更新;CAS 是CPU的并发原语!
System.out.println(atomicInteger.compareAndSet(2020, 2021));
//达到期望值更新成功
System.out.println(atomicInteger.get());
//更新后未达到期望值,更新失败
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
}
}

Unsafe类

java不能直接操作内存,但是可以调用c++,c++可以操作内存,java可以通过native关键字定义的方法来调用c++。Unsafe类就像是java留给自己的一个后门。所以Unsafe类中都是native方法和调用native方法的方法!

在原子类里,有一个getAndIncrement方法用作自增、那么他的底层是如何实现的呢?

其实就是调用的unsafe类中的getAndAddInt方法

public final int getAndIncrement() {
//dalta传入了1
return U.getAndAddInt(this, VALUE, 1);
}
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
//v每次都跟新为最新值,所以一直会是期望的值!就执行了++的操作
v = getIntVolatile(o, offset);
//如果当前对象o期望的值等于v,那么将当前对象o的值跟新为v+dalta;
} while (!weakCompareAndSetInt(o, offset, v, v + delta));
return v;
}
public final boolean weakCompareAndSetInt(Object o, long offset,
int expected,
int x) {
return compareAndSetInt(o, offset, expected, x);
}
public final native boolean compareAndSetInt(Object o, long offset,
int expected,
int x);

对比观察,其实getAndAddInt就是定义一个变量取到最新的值,然后通过while循环一直更新,其中getIntVolatile和compareAndSetInt都是通过java调用底层c++操作内存。

其中用到了一段标准的锁(自旋锁!):

 do {
//v每次都跟新为最新值,所以一直会是期望的值!就执行了++的操作
v = getIntVolatile(o, offset);
//如果当前对象o期望的值等于v,那么将当前对象o的值跟新为v+dalta;
} while (!weakCompareAndSetInt(o, offset, v, v + delta));

缺点

1、循环会耗时

2、一次性只能保证一个共享变量的原子性

3、会存在ABA问题

优点

自带原子性

CAS : ABA问题(狸猫换太子)!

package org.example.cas;

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
//JAVA CAS -> 比较并交换
//期望、更新
//compareAndSet(int expectedValue, int newValue)
//如果我期望的值达到了那么就跟新、否则就不更新; CAS 是CPU的并发原语!
//===============捣乱的线程================
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.compareAndSet(2021, 2020));
//达到期望值更新成功
System.out.println(atomicInteger.get());
//更新后未达到期望值,更新失败
//===============期望的线程================
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
//getAndIncrement number++ 底层如何实现的?
atomicInteger.getAndIncrement();//++方法 }
}

JUC并发编程学习笔记(十八)深入理解CAS的更多相关文章

  1. JUC并发编程学习笔记

    JUC并发编程学习笔记 狂神JUC并发编程 总的来说还可以,学到一些新知识,但很多是学过的了,深入的部分不多. 线程与进程 进程:一个程序,程序的集合,比如一个音乐播发器,QQ程序等.一个进程往往包含 ...

  2. 并发编程学习笔记(6)----公平锁和ReentrantReadWriteLock使用及原理

    (一)公平锁 1.什么是公平锁? 公平锁指的是在某个线程释放锁之后,等待的线程获取锁的策略是以请求获取锁的时间为标准的,即使先请求获取锁的线程先拿到锁. 2.在java中的实现? 在java的并发包中 ...

  3. 转: 【Java并发编程】之十八:第五篇中volatile意外问题的正确分析解答(含代码)

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17382679 在<Java并发编程学习笔记之五:volatile变量修饰符-意料之外 ...

  4. python3.4学习笔记(十八) pycharm 安装使用、注册码、显示行号和字体大小等常用设置

    python3.4学习笔记(十八) pycharm 安装使用.注册码.显示行号和字体大小等常用设置Download JetBrains Python IDE :: PyCharmhttp://www. ...

  5. Java并发编程学习笔记

    Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...

  6. 并发编程学习笔记(15)----Executor框架的使用

    Executor执行已提交的 Runnable 任务的对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等)分离开来的方法.通常使用 Executor 而不是显式地创建 ...

  7. 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理

    1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...

  8. 并发编程学习笔记(13)----ConcurrentLinkedQueue(非阻塞队列)和BlockingQueue(阻塞队列)原理

    · 在并发编程中,我们有时候会需要使用到线程安全的队列,而在Java中如果我们需要实现队列可以有两种方式,一种是阻塞式队列.另一种是非阻塞式的队列,阻塞式队列采用锁来实现,而非阻塞式队列则是采用cas ...

  9. 并发编程学习笔记(11)----FutureTask的使用及实现

    1. Future的使用 Future模式解决的问题是.在实际的运用场景中,可能某一个任务执行起来非常耗时,如果我们线程一直等着该任务执行完成再去执行其他的代码,就会损耗很大的性能,而Future接口 ...

  10. 并发编程学习笔记(12)----Fork/Join框架

    1. Fork/Join 的概念 Fork指的是将系统进程分成多个执行分支(线程),Join即是等待,当fork()方法创建了多个线程之后,需要等待这些分支执行完毕之后,才能得到最终的结果,因此joi ...

随机推荐

  1. KingbaseES V8R6集群运维案例之---repmgrd进程启动无法访问共享内存

    案例说明: KingbaseES V8R6集群在启动repmgrd进程时,出现'unable to write to shared memory'故障,导致repmgrd进程启动终止. 适用版本: K ...

  2. linux xfce 在文件管理器里点击运行shell脚本文件

    1.打开 Settings Editor 2.点击左边的 thunar 3.点击右边的 添加 ,在属性中输入 /misc-exec-shell-scripts-by-default 在类型中选择布尔类 ...

  3. 论文阅读小结(B/S和C/S结构)

    论文阅读小结 一.B/S 和 C/S 软件体系结构选择 1) C/S . B/S 结构概述 C/S 结构,即 Client/Server (客户机 / 服务器 ), C/S 结构软件分为客户机和服务器 ...

  4. 鸿蒙HarmonyOS实战-ArkUI组件(Radio)

    一.Radio Radio单选框是一种表单元素,允许用户从一组选项中选择一个选项.它由一个圆圈和一个标签组成,用户只能选择其中一个选项.Radio单选框通常用于表单中,用于收集用户选择的信息,例如用户 ...

  5. #贪心#CF605A Sorting Railway Cars

    题目 一个长度为 \(n\) 的排列,每次可以将一个数移至开头或者结尾,问最少多少次使其升序排列 分析 让数字连续的情况尽量多才能让移出来的次数尽量少, 找到最长的数字连续段,若其长度为 \(len\ ...

  6. 如何利用OpenHarmony ArkUI的Canvas组件实现涂鸦功能?

    简介 ArkUI是一套UI开发框架,提供了开发者进行应用UI开发时所需具备的能力.随着OpenAtom OpenHarmony(以下简称"OpenHarmony")不断更新迭代,A ...

  7. 全平台GPU通用AI视频补帧超分教程

    全平台GPU通用AI视频补帧超分教程 本教程只发布于https://www.cnblogs.com/Icys 注意:本教程需要一定的命令行和视频编码知识,请谨慎食用. 软件准备 realcugan-n ...

  8. Docker 学习之道: 容器注册表及其最佳实践

    容器注册表是Docker容器镜像的集中存储和分发系统.它允许开发人员以这些镜像的形式轻松共享和部署应用程序.容器注册表在容器化应用程序的部署中发挥着关键作用,因为它们提供了一种快速.可靠和安全的方式, ...

  9. C# Replace方法

    例子: string tStw = "Run Status"; string tStw1 = tStw.Replace("Run Status", " ...

  10. mongodb基础整理篇————聚合操作[三]

    前言 简单整理一下聚合操作. 正文 什么是聚合框架: 作用于一个或多个集合上 对集合的数据进行的一系列运算 将这些数据转换为期望的形式 从效果而言, 聚合框架相当于SQL 查询中的: Group By ...