Java多线程(5):CAS
您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~
在JDK1.5之前,Java的多线程都是靠synchronized来保证同步的,这会引起很多性能问题,例如死锁。但随着Java的不断完善,JNI(Java Native Interface)使得Java能越过JVM直接调用本地方法,例如CAS。
CAS是Compare And Swap(比较与交换)的缩写,它用于实现多线程同步的原子指令,允许算法执行读-修改-写操作,而无需担心其他线程同时修改变量。说人话,意思就是它的操作过程足够细微,以至于线程都奈何不了它。
所谓原子指令就是指不会被线程调度机制打断的操作指令,这种操作一旦开始,就一直运行到结束,中间不会有任何线程切换,即要么全部完成,要么全部中断。换一种说法,就是CAS可以保证Java运算实现我们想要的操作而无需担心会受到多线程的影响。
某种程度上,CAS可以用来取代synchronized的强制同步,提升性能。其实整个java.util.concurrent包都是建立在CAS之上的,尤其是Java中大多数锁的实现基类AbstractQueuedSynchronizer,更是以CAS为基础,提供了一系列的独占锁、共享锁、可重入锁、自旋锁、读写锁等多线程控制手段(这在后面会说)。就像图中那样:

Java对CAS的实现都在java.util.concurrent.atomic包下(java.util.concurrent也简称JUC,这是个简称。所以如果有面试官说想让你谈谈JUC相关的问题,不要一脸懵,否则会被立即淘汰)。以AtomicInteger为例,从源码可以看出CAS操作都是通过sun包下Unsafe类实现,而Unsafe类中的方法都是native方法,由本地实现,和操作系统、CPU都有关系。CAS有一个比较通用的实现模式:
1、首先声明(共享)变量为volatile
2、然后使用CAS的原子条件来更新
3、同时配合volatile的可见性来实现线程之间的同步
前面讲过,不用深究volatile关键字的用途,因为随着机器配置的豪华,其实这个关键字已经没啥用了,而且也可以看到,在CAS里面也有大量出现,JDK已经替你用好了,自己如果不太熟悉就不要用了。CAS相关类结构图是:

还是老规矩,用代码来举例:
/**
* 仅用AtomicInteger实现CAS
*
* @author 湘王
*/
public class AtomicIntegerTester1 {
// 使用AtomicInteger实现CAS,有没有volatile都不影响
public static volatile AtomicInteger atomicInteger = new AtomicInteger(0); public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(3); for (int i = 0; i < 20; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
atomicInteger.getAndIncrement();
}
};
executor.submit(runnable);
} // 为了观察效果休眠,但实际生产环境中肯定不允许
Thread.sleep(100);
executor.shutdown();
System.out.println(atomicInteger.get());
}
} /**
* 用AtomicIntegerFieldUpdater实现CAS
*
* @author 湘王
*/
public class AtomicIntegerTester2 {
/*
* 使用AtomicIntegerFieldUpdater实现CAS,相关计算字段必须用volatile修饰,不然抛异常
* Caused by: java.lang.IllegalArgumentException: Must be volatile type
*
*/
public volatile int count = 0;
public static final AtomicIntegerFieldUpdater<AtomicIntegerTester2> lockUpdate = AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerTester2.class, "count"); public int increase(int inc) {
return lockUpdate.addAndGet(this, inc);
} public int get() {
return lockUpdate.get(this);
} public static void main(String[] args) throws InterruptedException {
AtomicIntegerTester2 tester = new AtomicIntegerTester2();
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 20; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
tester.increase(1);
}
};
executor.submit(runnable);
}
// 为了观察效果休眠,但实际生产环境中肯定不允许
Thread.sleep(100);
executor.shutdown();
System.out.println(tester.get());
}
}
CAS的内容并不多,可以看看它的源码,还是比较有意思的。
感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~
Java多线程(5):CAS的更多相关文章
- Java多线程:CAS与java.util.concurrent.atomic
锁的几种概念 悲观锁 总是假设最坏的情况,每次获取数据都认为别人会修改,所以拿数据时会上锁,一直到释放锁不允许其他线程修改数据.Java中如synchronized和reentrantLock就是这种 ...
- Java多线程系列——原子类的实现(CAS算法)
1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...
- java 多线程12 : 无锁 实现CAS原子性操作----原子类
由于java 多线程11:volatile关键字该文讲道可以使用不带锁的情况也就是无锁使变量变成可见,这里就理解下如何在无锁的情况对线程变量进行CAS原子性及可见性操作 我们知道,在并发的环境下,要实 ...
- Java多线程并发06——CAS与AQS
在进行更近一步的了解Java锁的知识之前,我们需要先了解与锁有关的两个概念 CAS 与 AQS.关注我的公众号「Java面典」了解更多 Java 相关知识点. CAS(Compare And Swap ...
- Java多线程--CAS
在Java多线程并发的情况下同时对一个变量进行操作会出现线程安全的问题,假如我们现在使用20个线程对一个变量不停累加1,代码如下: 1 public class ThreadDemo implemen ...
- 40个Java多线程问题总结
前言 Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行 ...
- Java多线程系列--“JUC锁”03之 公平锁(一)
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
- Java多线程系列--“JUC锁”04之 公平锁(二)
概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...
- java多线程系类:JUC线程池:03之线程池原理(二)(转)
概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...
- java多线程系类:JUC原子类:03之AtomicLongArray原子类
概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...
随机推荐
- Excel 运算符(四):引用运算符
引用运算符用于将单元格区域合并运算,包括:冒号.,逗号. 空格. : 运算 :运算符用于定义一个连续的数据区域,例如"A1:B3",表示从 A1 到 B3 的 6 个单元格. 并集 ...
- 小技巧---eclipse 全选lib jar包
按住shift键,点击第一个jar包,然后点击最后一个jar包,就全选了所有jar包,然后添加build path 添加到类路径
- LeetCode 593. 有效的正方形(向量做法)
题目 题目链接:593. 有效的正方形 题意:给出二维平面上四个点的坐标,判断这四个点是否能构成一个正方形,四个点的输入顺序不做任何保证. 思路 通过向量运算可以很轻松地解决这道题.任取一点向其他三点 ...
- 浅析websocket的基本应用spring boot + vue +C# + WPF
1.基本概念 首先websocket是基于H5的一种通信.在网页中如果定时获取服务器端的实时数据,我们常采用long poll 和ajax轮询的方式.但是在轮询过程中,由于根本没有新数据的改变,而造成 ...
- Oracle_FDW 使用介绍
本文以例子的形式介绍 KingbaseES(Postgresql)数据库如何通过 oracle_fdw 扩展访问Oracle数据库.以下例子在PG12.3 与 KingbaseES V8R6进行过实际 ...
- 硬核解析MySQL的MVCC实现原理,面试官看了都直呼内行
1. 什么是MVCC MVCC全称是Multi-Version Concurrency Control(多版本并发控制),是一种并发控制的方法,通过维护一个数据的多个版本,减少读写操作的冲突. 如果没 ...
- java的URI和URL的关系
java的URI和URL到底是什么 在我们做开发时,经常有URI和URL弄混的问题,如果当时直接看URI和URL的源码就不可能弄混.首先我总结一下URI和URL的关系:他们的关系是:URL是一种特殊的 ...
- Eclipse配置Tomcat搭建java Web (JSP)开发环境
配置Tomcat服务 1.打开窗口-首选项-Server-Runtiome Environments 2.点击ADD,选择对应的Tomcat版本,点击下一步 路径选择Tomcat解压后的文件夹目录,点 ...
- 2.2 virtualenv 虚拟环境
有的时候因为各种原因,在操作系统下,我们会安装很多版本的Python解释器.同样,我们也有可能因为各种原因,需要不同版本的模块,比如Django1.8,Django1.11.再加上pip工具管理器的版 ...
- 使用读写分离模式扩展 Grafana Loki
转载自:https://mp.weixin.qq.com/s?__biz=MzU4MjQ0MTU4Ng==&mid=2247500127&idx=1&sn=995987d558 ...