JUC并发编程学习笔记(十八)深入理解CAS
深入理解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的更多相关文章
- JUC并发编程学习笔记
JUC并发编程学习笔记 狂神JUC并发编程 总的来说还可以,学到一些新知识,但很多是学过的了,深入的部分不多. 线程与进程 进程:一个程序,程序的集合,比如一个音乐播发器,QQ程序等.一个进程往往包含 ...
- 并发编程学习笔记(6)----公平锁和ReentrantReadWriteLock使用及原理
(一)公平锁 1.什么是公平锁? 公平锁指的是在某个线程释放锁之后,等待的线程获取锁的策略是以请求获取锁的时间为标准的,即使先请求获取锁的线程先拿到锁. 2.在java中的实现? 在java的并发包中 ...
- 转: 【Java并发编程】之十八:第五篇中volatile意外问题的正确分析解答(含代码)
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17382679 在<Java并发编程学习笔记之五:volatile变量修饰符-意料之外 ...
- python3.4学习笔记(十八) pycharm 安装使用、注册码、显示行号和字体大小等常用设置
python3.4学习笔记(十八) pycharm 安装使用.注册码.显示行号和字体大小等常用设置Download JetBrains Python IDE :: PyCharmhttp://www. ...
- Java并发编程学习笔记
Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...
- 并发编程学习笔记(15)----Executor框架的使用
Executor执行已提交的 Runnable 任务的对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等)分离开来的方法.通常使用 Executor 而不是显式地创建 ...
- 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理
1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...
- 并发编程学习笔记(13)----ConcurrentLinkedQueue(非阻塞队列)和BlockingQueue(阻塞队列)原理
· 在并发编程中,我们有时候会需要使用到线程安全的队列,而在Java中如果我们需要实现队列可以有两种方式,一种是阻塞式队列.另一种是非阻塞式的队列,阻塞式队列采用锁来实现,而非阻塞式队列则是采用cas ...
- 并发编程学习笔记(11)----FutureTask的使用及实现
1. Future的使用 Future模式解决的问题是.在实际的运用场景中,可能某一个任务执行起来非常耗时,如果我们线程一直等着该任务执行完成再去执行其他的代码,就会损耗很大的性能,而Future接口 ...
- 并发编程学习笔记(12)----Fork/Join框架
1. Fork/Join 的概念 Fork指的是将系统进程分成多个执行分支(线程),Join即是等待,当fork()方法创建了多个线程之后,需要等待这些分支执行完毕之后,才能得到最终的结果,因此joi ...
随机推荐
- springboot mybatis 多数据源整合
1.在application.properties中配置两个数据库: # db01 database spring.datasource.db01.jdbc-url=jdbc:oracle:thin: ...
- UE4中的C++编程简介
对官方文档的学习链接 利用UE创建一个C++基类 在编辑器中可以选择父类,根据这个父类我们可以创建一个基类用于后续的蓝图类制作. 以Actor父类为例创建基类,其头文件会包含一个构造函数,一个Tick ...
- 福州大学MEM 备考总结
自己的基本情况 2022年8月2日,当天觉得休息的差不多了,思来想去,觉得考研是个不错的选择,和女朋友聊了一下,得到她的支持,于是乎定下目标.接着就是开始在网络上查找相关的材料,先把要报考高校和专业的 ...
- 使用 MediaStream Recording API 和 Web Audio API 在浏览器中处理音频(未完待续)
使用 MediaStream Recording API 和 Web Audio API 在浏览器中处理音频 1. 背景 最近项目上有个需求,需要实现:录音.回放录音.实现音频可视化效果.上传wav格 ...
- Vue3 Diff 之 patchKeyedChildren 动态示例
在学习全网学习各路大神的关于Vue3 Diff算法分析文章的时候,一定离不开关键方法 patchKeyedChildren. patchKeyedChildren 处理的场景比较多,大致有 5 个主要 ...
- #Dijkstra,二进制拆位#洛谷 5304 [GXOI/GZOI2019]旅行者
题目 分析(\(logk\)次Dijkstra) 首先为什么\(O(nklogn)\)的多次\(dijkstra\)为什么会TLE, 因为中间有许多的冗余状态,即使两点求出的路径是最短的,它也不一定是 ...
- #dp#洛谷 2679 子串
题目 有两个仅包含小写英文字母的字符串 \(A\) 和 \(B\). 现在要从字符串 \(A\) 中取出 \(k\) 个互不重叠的非空子串,然后把这 \(k\) 个子串按照其在字符串 \(A\) 中出 ...
- 使用OHOS SDK构建libsamplerate
参照OHOS IDE和SDK的安装方法配置好开发环境. 从github下载源码. 执行如下命令: git clone --depth=1 https://github.com/libsndfile/l ...
- [AHOI2014/JSOI2014/一本通1722]骑士游戏 题解 (spfa做dp)
题目描述 在游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻击.两种攻击方式都会消耗JYY一些体力.采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个 ...
- keycloak~网站对接到Keycloak的步骤
新网站对接到KC的部署 kc的环境 向kc申请自己的客户端 kc的登录接口 通过code换token接口 刷新token接口 kc的用户信息接口 kc的jwt token说明 1. kc的环境 测试环 ...